UVA 11008 Antimatter Ray Clearcutting

狀態DP,以dp[i]記錄砍掉的樹的狀態爲 i 時的最少發射激光數,對於每個狀態考慮將當前狀態下未被砍的樹中選一顆來砍,則考慮兩種情況,一個是這顆樹需要單獨一束激光來砍,另一個就是這棵樹和其他已經被砍的某一顆樹形成一條線,而在這條線上的點都可以被砍掉,所以求砍這個方向的前一個狀態時需要將在這條線上的點都減掉。

具體說明看代碼:

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <cstdlib>
#include <algorithm>
using namespace std;
//typedef __int64 int64;
typedef long long ll;
#define M 100005
#define max_inf 0x7f7f7f7f
#define min_inf 0x80808080
#define mod 1000000007

int n , m , x[25] , y[25];
int dp[1<<22];

bool Judge(int k)//判斷當前狀態砍掉的樹時多少棵樹
{
	int num = 0;
	while (k)
	{
		num += (k&1);
		k >>= 1;
	}
	return m <= num;
}

void Solve()
{
	int i , j , k , l , up = 1<<n , tp[25] , ans = max_inf;
	memset(dp , max_inf , sizeof dp);
	dp[0] = 0;
	for (i = 0 ; i < up ; i++)
	{
		for (j = 0 ; j < n ; j++)
		{
			if (i & (1<<j))continue;//若第j顆樹已經在狀態i中,則繼續
			int next = i+(1<<j);//砍掉這棵樹後的下一個狀態
			dp[next] = min(dp[next],dp[i]+1);

			int temp = i , cnt = 0;
			for (k = 0 ; k < n ; k++)//記錄狀態i裏,被砍掉的樹
			{
				if (temp&1)tp[cnt++] = k;
				temp >>= 1;
			}


			for (k = 0 ; k < cnt ; k++)//確定一個方向
			{
				temp = i;
				for (l = 0 ; l < cnt ; l++)
				{
					//將這個方向上的點都減掉
					if ( (y[j]-y[tp[k]])*(x[tp[l]]-x[j]) == (x[j]-x[tp[k]])*(y[tp[l]]-y[j]) ) temp -= (1<<tp[l]);
				}
				dp[next] = min(dp[next] , dp[temp]+1);
			}
		}
		if (Judge(i))ans = min(ans,dp[i]);
	}
	printf("%d\n",ans);
}

int main()
{
	int t , i , tcase = 1;
	scanf("%d",&t);
	while (t--)
	{
		scanf("%d%d",&n,&m);
		for (i = 0 ; i < n ; i++)scanf("%d%d",x+i,y+i);
		if (tcase > 1)printf("\n");
		printf("Case #%d:\n",tcase++);
		Solve();
	}
	return 0;
}


 

發佈了98 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章