UVA - 11008 Antimatter Ray Clearcutting

题目大意:有一篇森林,给出n棵树的坐标,现在有一种反物质光线,可以清楚直线上的树木,然后给出m,代表这片森林要除掉m棵树,问最少使用几次光线。


解题思路:状态压缩,要用位运算去做,下面介绍一篇写的比较好的题解。

http://www.cnblogs.com/scau20110726/archive/2012/09/28/2707866.html



#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int INF = 0x3f3f3f3f;
int m, n, DP[(1<<16)+100], x[20], y[20];

bool judge(int i, int j, int k) {
	int a = x[i] - x[j], b = y[i] - y[j];
	int c = x[j] - x[k], d = y[j] - y[k];
	return a * d == b * c;
}

int DPS(int k, int st) {
	if (DP[st] != INF)
		return DP[st];
	if (k <= 0)
		return 0;
	if (k == 1)
		return DP[st] = 1;

	for (int i = 0; i < n; i++) if ((1<<i) & st)
		for (int j = i + 1; j < n; j++) if ((1<<j) & st) {
			int t = st, cnt = 0;
			for (int r = i; r < n; r++) if ((1<<r) & st && judge(i, j, r)) {
				t -= (1<<r);
				cnt++;
			}
			DP[st] = min(DP[st], DPS(k - cnt, t) + 1);
		}

	return DP[st];
}

int main() {
	int T, kase = 0;
	scanf("%d",&T);
	while (T--) {
		scanf("%d%d", &n, &m);
		for (int i = 0; i < n; i++)
			scanf("%d%d", &x[i], &y[i]);
		if (kase) printf("\n");
		memset(DP, INF, sizeof(DP));
		printf("Case #%d:\n", ++kase);
		printf("%d\n", DPS(m, (1<<n)-1));
	}
	return 0;
}


你可能感兴趣的:(UVA - 11008 Antimatter Ray Clearcutting)