今天写了一个多小时,才把状压dp写好。(还是在DY的指导下完成的)
但是,却也总结了一些知识:
1.对于以前的0~n-1和1~n的差别不清楚,原来只不过是最后一位的使用,但内存差距较大。
2.对于位运算的理解,又提升了一个层次,还是不错的。
3.对与状压dp的基础理解又加深了。
4.对于状压的预处理也是利用2进制来表示
5.状压dp也可以用dfs来进行解决
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define ak(aa) memset(aa,0,sizeof(aa))
#define For(aa,bb,cc) for(int aa=bb;aa<=cc;++aa)
using namespace std;
const int maxn=1<<18,inf=0x3f3f3f3f;
int dp[maxn];
int line[20][20];
int n;
struct node{
int x,y;
}a[20];
/*
dp[]中用0表示已经被抹除,1表示还未被抹除
line[i][j]用1表示这个点在i,j之间的连线上,0表示不在
*/
void prepare(){
For(i,1,n){
For(j,i+1,n){
int lx=a[i].x-a[j].x,ly=a[i].y-a[j].y;
line[i][j]=(1<<i)|(1<<j);
For(k,j+1,n){
int mx=a[i].x-a[k].x,my=a[i].y-a[k].y;
if(lx*my==mx*ly){
line[i][j]|=(1<<k);
}
}
line[j][i]=line[i][j];
}
}
return ;
}
int dfs(int now){
if(dp[now]<inf) return dp[now];
int num=__builtin_popcount(now);//查找1 的个数
if(num<=2) return 1;
int i=1;
while(!(now&(1<<i))) ++i;//找到第一个存在的点
For(j,i+1,n){//进行枚举点
if(now&(1<<j))
dp[now]=min(dp[now],dfs(now&(~line[i][j]))+1);
}
return dp[now];
}
void work(int now){
memset(dp,inf,sizeof(dp));
dp[0]=0;//初值
scanf("%d",&n);
For(i,1,n){
scanf("%d%d",&a[i].x,&a[i].y);
}
prepare();
printf("Case %d: ",now);
printf("%d\n",dfs((1<<n+1)-2));//全集要设定好
return ;
}
int main(){
int _;
scanf("%d",&_);
For(i,1,_) work(i);
return 0;
}