LightOJ1018 Brush (IV)(状压DP)

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

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

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

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

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int d[1<<16],sta[16][16];
 7 int main(){
 8     int t,n,x[16],y[16];
 9     scanf("%d",&t);
10     for(int cse=1; cse<=t; ++cse){
11         scanf("%d",&n);
12         for(int i=0; i<n; ++i){
13             scanf("%d%d",x+i,y+i);
14         }
15         if(n==1){
16             printf("Case %d: %d\n",cse,1);
17             continue;
18         }
19         for(int i=0; i<n; ++i){
20             for(int j=0; j<n; ++j){
21                 if(i==j){
22                     sta[i][j]=(1<<i);
23                     continue;
24                 }
25                 int s=0;
26                 for(int k=0; k<n; ++k){
27                     if((x[i]-x[j])*(y[j]-y[k])==(x[j]-x[k])*(y[i]-y[j])){
28                         s|=(1<<k);
29                     }
30                 }
31                 sta[i][j]=s;
32             }
33         }
34         memset(d,127,sizeof(d));
35         d[0]=0;
36         for(int i=0; i<(1<<n)-1; ++i){
37             if(d[i]>10000) continue;
38             int j=0;
39             while(j<n){
40                 if((i>>j&1)==0) break;
41                 ++j;
42             }
43             for(int k=0; k<n; ++k){
44                 if((i>>k&1)==0){
45                     d[i|sta[j][k]]=min(d[i|sta[j][k]],d[i]+1);
46                 }
47             }
48         }
49         printf("Case %d: %d\n",cse,d[(1<<n)-1]);
50     }
51     return 0;
52 }

 

posted @ 2016-07-10 15:23  WABoss  阅读(252)  评论(0编辑  收藏  举报