LightOJ1018 Brush (IV)(状压DP)

时间:2024-04-25 14:15:03

题目大概说一个平面有n个灰尘,可以用一把刷子直直刷过去清理直线上的所有灰尘,问最少要刷几下才能清理完所有灰尘。

  • 首先怎么刷其实是可以确定的,或者说直线有哪些是可以确定的,而最多就有C(n,2)条不一样的直线,即16*15/2=120;
  • 然后容易想到用状压DP求解,d[S]表示已经清理的灰尘的状态是S最少刷的次数;
  • 而转移就是通过枚举接下来使用那条直线,用我为人人的方式转移,
  • 另外直线包含的灰尘集合状态一开始就可以预处理出来,这样时间复杂度O(2n*n2)。

不过超时,超了800多ms。实在想不出怎么没办法。而看了网上,也是一样思路,不过转移是任意选出一个没有在S中的点,然后枚举另一个没有在S的端点,通过添加这两点构成的直线去转移,时间复杂度O(2n*n)。

我表示不解。。这样有些状态会漏吧???

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; int d[<<],sta[][];
int main(){
int t,n,x[],y[];
scanf("%d",&t);
for(int cse=; cse<=t; ++cse){
scanf("%d",&n);
for(int i=; i<n; ++i){
scanf("%d%d",x+i,y+i);
}
if(n==){
printf("Case %d: %d\n",cse,);
continue;
}
for(int i=; i<n; ++i){
for(int j=; j<n; ++j){
if(i==j){
sta[i][j]=(<<i);
continue;
}
int s=;
for(int k=; k<n; ++k){
if((x[i]-x[j])*(y[j]-y[k])==(x[j]-x[k])*(y[i]-y[j])){
s|=(<<k);
}
}
sta[i][j]=s;
}
}
memset(d,,sizeof(d));
d[]=;
for(int i=; i<(<<n)-; ++i){
if(d[i]>) continue;
int j=;
while(j<n){
if((i>>j&)==) break;
++j;
}
for(int k=; k<n; ++k){
if((i>>k&)==){
d[i|sta[j][k]]=min(d[i|sta[j][k]],d[i]+);
}
}
}
printf("Case %d: %d\n",cse,d[(<<n)-]);
}
return ;
}