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 }

 

转载于:https://www.cnblogs.com/WABoss/p/5657764.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值