试题 算法提高 Sharing Chocolate
资源限制
时间限制:1.0s 内存限制:128.0MB
问题描述
每天,巧克力在它的许多形式上被全世界数百万人分享。它是一个真正普遍的糖果,实际上在世界上每个国家都能得到。
你发现唯一比吃巧克力更好的事情是把它分享给朋友。不幸的是,你的朋友非常挑剔,有着不同的胃口:有的喜欢让你提供较多的巧克力,而其他的喜欢让你提供较少的巧克力。你发现当他们的要求可以相互叠加时,这个事情就变得越来越难决断。现在是写一个程序来一次性完全解决这个问题的时间!
你的巧克力是矩形的。巧克力由同样大小的矩形块组成。你可以沿着巧克力中行或者列的分割线将巧克力分成两块来分享你的巧克力。你可以重复地用同样手段将分成的小块继续分割。你的每个朋友坚持要得到巧克力中的一个矩形部分,这个部分包含一个确定地小块数。你也有些坚持心:如果这块巧克力能全部分给你的朋友,不剩下任何部分,你才会分割你的巧克力。
例如图9表示将一个由3×4个小块组成巧克力块分割3次,分成各自包含6、3、2、1个小块的4部分的一种方法。(这相当于输入样例中第一个测试数据。)
输入格式
输入数据包含多组测试数据,每组测试数据描述一个要分享的巧克力块。每组测试数据的第一行包含一个整数n(1<=n<=15),表示巧克力需要分割成的块数。第二行包含两个整数x、y,表示巧克力块的两个方向上的长度。第三行包含n个正整数,表示n个部分各自需要包含的小块数。
输入数据终止于只包含整数0的一行。
输出格式
对于每组测试数据,先输出它的测试点编号。然后输出将巧克力按照指定的方法分割是否有可能:如果可能,输出“Yes”,否则输出“No”。按照输出样例中的格式输出。
样例输入
4
3 4
6 3 2 1
2
2 3
1 5
0
样例输出
Case 1: Yes
Case 2: No
数据规模和约定
对于40%的数据,1<=n<=5,1<=x,y<=10;
对于全部的数据,1<=n<=15,1<=x,y<=100,输入文件保证测试点个数不超过10。
实现代码
#include<iostream>
#include<cstring>
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
int sum[1 << 15], dp[1 << 15][105], maxn, ans;
int bitcount(int x) { return !x ? 0 : bitcount(x >> 1) + (x & 1); } //计算有几个状态符合
int cal(int s, int x) {
if (dp[s][x] != -1) return dp[s][x];
if (bitcount(s) == 1) return dp[s][x] = 1;
int y = sum[s] / x;
for (int a = (s - 1) & s; a; a = (a - 1)& s) { //分到只剩下一块就不能分,本身没有的块也不能分出来
int b = (s ^ a);
if (sum[a] % x == 0 && cal(a, min(x, sum[a] / x)) && cal(b, min(x, sum[b] / x))) return dp[s][x] = 1;
if (sum[a] % y == 0 && cal(a, min(y, sum[a] / y)) && cal(b, min(y, sum[b] / y))) return dp[s][x] = 1;
}
return dp[s][x] = 0;
}
int main() {
int n, r, c, tmp, cnt = 0;
while (cin >> n && n) {
memset(dp, -1, sizeof(dp));
memset(sum, 0, sizeof(sum));
maxn = (1 << n) - 1;
cin >> r >> c;
for (int i = 0; i < n; i++) {
cin >> tmp;
for (int j = 0; j <= maxn; j++) if (j & (1 << i)) sum[j] += tmp;
}
ans = r * c != sum[maxn] ? 0 : cal(maxn, min(r, c));
cout << "Case " << ++cnt << ": " << (ans ? "Yes" : "No") << endl;
}
return 0;
}