标签:http io for ar 代码 amp line ef
题目:uva11008 - Antimatter Ray Clearcutting(二进制+记忆化搜索)
题目大意:给出n棵树的坐标,每次砍树能够将在同一直线上的树一起砍掉,然后给出要求你至少砍掉的树的数量,问你要达到这个要求需要砍多少次。
解题思路:因为这题的树的数量比较小(16), 并且只有砍和不砍两种选择,可以用二进制数将状态表示出来。大致思路是:每次都将当前状态下的还没砍的树中选择两棵,在将和这两个树在同一直线上的树一起砍掉,得到新的状态。如果已经》=K棵了,就可以返回0了。一般来说,每次选择两棵树一起砍掉比较优,除非只剩下一棵树了。所以应该要先预处理出每两棵树和它们在同一直线上的树,并且这个状态可以也用二进制表示。
代码:
#include <cstdio>
#include <cstring>
const int maxn = 1<<17;
const int M = 20;
int dp[maxn];
int n, k;
int tree[M][2];
int line[M][M];
bool judge (int i, int j, int k) {
int a = (tree[j][1] - tree[i][1]) * (tree[k][0] - tree[j][0]);
int b = (tree[k][1] - tree[j][1]) * (tree[j][0] - tree[i][0]);
return a == b ? true : false;
}
int Min (const int a, const int b) { return a < b ? a: b; }
void init () {
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
line[i][j] = 0;
for (int l = 0; l < n; l++) {
if (judge (i, j, l)) {
line[i][j] |= (1<<l);
}
}
}
}
for (int i = 0; i <= (1<<n); i++)
dp[i] = M;
}
int count (int s) {
int ans = 0;
for (int i = 0; i < n; i++)
if (s & (1<<i))
ans++;
return ans;
}
int DP (int s) {
int& ans = dp[s];
if (ans != M)
return ans;
if (count (s) >= k)
return ans = 0;
int flag = 0;
for (int i = 0; i < n; i++) {
if (((1 << i) & s) == 0) {
for (int j = i + 1; j < n; j++) {
if (((1 << j) & s) == 0) {
flag = 1;
ans = Min (ans, DP(s | line[i][j]) + 1);
//printf ("%d %d %d\n", s, s | line[i][j], ans);
}
}
if (!flag) {
ans = Min (ans, DP(s | (1<<i)) + 1);
}
}
}
return ans;
}
int main () {
int t;
scanf ("%d", &t);
for (int i = 1; i <= t; i++) {
scanf ("%d%d", &n, &k);
for (int j = 0; j < n; j++)
scanf ("%d%d", &tree[j][0], &tree[j][1]);
init ();
printf ("Case #%d:\n", i);
printf ("%d\n", DP(0));
if (i != t)
printf ("\n");
}
return 0;
}uva11008 - Antimatter Ray Clearcutting(二进制+记忆化搜索),布布扣,bubuko.com
uva11008 - Antimatter Ray Clearcutting(二进制+记忆化搜索)
标签:http io for ar 代码 amp line ef
原文地址:http://blog.csdn.net/u012997373/article/details/38641853