告诉你若干个(<=100)武器的花费以及武器能消灭的怪物编号,问消灭所有怪物(<=100)的最小花费。。。当然每个武器可以无限次使用,不然这题就太水了╮(╯▽╰)╭
这题当时比赛的时候连题都还没看就结束了。。。。赛后一看,果断是重复覆盖。。。
不过之后一直没敲。。。然后今天算是补回来吧,同时也把好久以前学的DLX复习一下。。。
DLX的话,双向十字链表。。。具体的话,百度Google什么的dancing links。。。
一开始敲的时候还是挺顺利的,因为之前做过几次重复覆盖都是直接拿精确覆盖的模板来改。。。差不多的,不过重复覆盖就删列,代码好像还少几行呢。。。不过有时调一会有时wa上一两发。。。又鉴于最近好像好多重复覆盖的题。。。就好像spfa一样频繁出现=。=个人感觉不科学。。。
而且之前那个精确覆盖的模板实在是无法直视,太挫了写得╮(╯▽╰)╭
重点来了~~~代码写好了,可是不AC╮(╯▽╰)╭太可恶了。。。。让JM帮忙看代码。。。于是苦逼地一直找bug。。。。
经过一小时吧大概的奋斗。。。JM发现。。。一个非常好笑的呵呵的亮点。。。。memset(vis,false,sizeof(false));。。。笑死我了。。。还好这是平时随便敲。。。
然后就AC了~~~
复杂度。。不知道怎么算DLX的复杂度哎~~~求高手教,或者说一般N,M多少可以~~
总结就是,打代码要仔细。。。。总之不要犯这种逗比错误。。。。真正比赛的时候就笑不出来了~~~啦啦啦~~~谢谢JM~~~

1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <string> 7 #include <vector> 8 #include <queue> 9 #include <set> 10 using namespace std; 11 12 #define ll long long 13 #define eps 1e-8 14 #define mod 21092013 15 16 #define inf 0x3f3f3f3f 17 #define maxr 110 18 #define maxn (maxr*maxr) 19 int n,m; 20 int L[maxn],R[maxn],U[maxn],D[maxn],cnt; 21 int row[maxn],col[maxn]; 22 int N[maxr],use[maxr],head[maxr]; 23 void init(){ 24 memset(head,-1,sizeof(head)); 25 memset(N,0,sizeof(N)); 26 for(int i=0;i<=m;++i){ 27 L[i]=i-1,R[i]=i+1; 28 U[i]=D[i]=i; 29 row[i]=0,col[i]=i; 30 } 31 L[0]=m,R[m]=0; 32 cnt=m; 33 } 34 void remove(int x){// 删除列 35 for(int i=D[x];i!=x;i=D[i]) 36 L[R[i]]=L[i],R[L[i]]=R[i]; 37 } 38 void resume(int x){// 恢复列 39 for(int i=D[x];i!=x;i=D[i]) 40 L[R[i]]=R[L[i]]=i; 41 } 42 int low(){ 43 int mi=maxr,idx=0; 44 for(int i=R[0];i;i=R[i])if(N[i]<mi)mi=N[i],idx=i; 45 return idx; 46 } 47 void link(int r,int c){ 48 ++N[c],++cnt; 49 row[cnt]=r,col[cnt]=c; 50 U[cnt]=U[c],D[cnt]=c; 51 U[D[cnt]]=D[U[cnt]]=cnt; 52 if(head[r]==-1) 53 head[r]=L[cnt]=R[cnt]=cnt; 54 else { 55 L[cnt]=L[head[r]]; 56 R[cnt]=head[r]; 57 L[R[cnt]]=R[L[cnt]]=cnt; 58 } 59 } 60 int cost[maxr]; 61 int ans; 62 void dance(int dep,int val){ 63 if(R[0]==0){ 64 ans = min(ans,val); 65 return ; 66 } 67 int c=low(); 68 if(c==0||val>=ans)return ; 69 for(int i=D[c];i!=c;i=D[i]){ 70 use[dep]=i; 71 remove(i); 72 for(int j=R[i];j!=i;j=R[j])remove(j); 73 dance(dep+1,val+cost[row[i]]); 74 for(int j=L[i];j!=i;j=L[j])resume(j); 75 resume(i); 76 } 77 } 78 79 int main(){ 80 while(~scanf("%d%d",&m,&n)){ 81 init(); 82 bool vis[maxr]; 83 memset(vis,false,sizeof(vis)); 84 ans=0; 85 for(int i=1;i<=n;++i){ 86 int tmp,tmp2; 87 scanf("%d%d",cost+i,&tmp); 88 ans+=cost[i]; 89 for(int j=0;j<tmp;++j){ 90 scanf("%d",&tmp2); 91 vis[tmp2]=true; 92 link(i,tmp2); 93 } 94 } 95 for(int i=1;i<=m;++i)if(vis[i]==false){vis[1]=false;break;} 96 if(vis[1]==false){puts("-1");continue;} 97 dance(0,0); 98 printf("%d ",ans); 99 } 100 return 0; 101 }
Note: 之后想起在cf上有一题类似的,当时用DLX重复覆盖超时了,要DP,然后再去试一下。。。
结果发现有一些数据会卡掉这份代码
在这里征求高手解答。。。。这种数据要怎么过。。。
我的想法是预处理weapon[i]能否完全代替weapon[j]或weapon[j]+weapon[k]...不过万一他要weapon[i]+weapon[j]才能完全代替weapon[k]+weapon[l]呢...好乱...
求高手解答....

1 void data(){ 2 freopen("in.txt","w",stdout); 3 puts("33 99"); 4 for(int i=0;i<99;++i) 5 if(i<33)printf("%d %d %d ",998,1,i%33+1); 6 else if(i<66)printf("%d %d %d %d ",998,2,i%33+1,(i+1)%33+1); 7 else printf("%d %d %d %d %d ",998,3,i%33+1,(i+1)%33+1,(i+2)%33+1); 8 }
参考了网上http://blog.sina.com.cn/s/blog_51cea4040100gwpv.html的剪枝优化。。。果然可以了。。。。可以跑出以上这种data了。。而且在fzu上的时间也从400+ms变成200+ms..排到第一了...有收获的感觉就是不错..这个剪枝感觉不错,好感动。。。泪牛满面,就是,当前价值+下界(不是下确界)>=best。。thank JM...

1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <string> 7 #include <vector> 8 #include <queue> 9 #include <set> 10 using namespace std; 11 12 #define ll long long 13 #define eps 1e-8 14 #define mod 21092013 15 16 #define inf 0x3f3f3f3f 17 #define maxr 110 18 #define maxn (maxr*maxr) 19 int n,m; 20 int L[maxn],R[maxn],U[maxn],D[maxn],cnt; 21 int row[maxn],col[maxn]; 22 int N[maxr],use[maxr],head[maxr]; 23 void init(){ 24 memset(head,-1,sizeof(head)); 25 memset(N,0,sizeof(N)); 26 for(int i=0;i<=m;++i){ 27 L[i]=i-1,R[i]=i+1; 28 U[i]=D[i]=i; 29 row[i]=0,col[i]=i; 30 } 31 L[0]=m,R[m]=0; 32 cnt=m; 33 } 34 void remove(int x){// 删除列 35 for(int i=D[x];i!=x;i=D[i]) 36 L[R[i]]=L[i],R[L[i]]=R[i]; 37 } 38 void resume(int x){// 恢复列 39 for(int i=D[x];i!=x;i=D[i]) 40 L[R[i]]=R[L[i]]=i; 41 } 42 int low(){ 43 int mi=maxr,idx=0; 44 for(int i=R[0];i;i=R[i])if(N[i]<mi)mi=N[i],idx=i; 45 return idx; 46 } 47 void link(int r,int c){ 48 ++N[c],++cnt; 49 row[cnt]=r,col[cnt]=c; 50 U[cnt]=U[c],D[cnt]=c; 51 U[D[cnt]]=D[U[cnt]]=cnt; 52 if(head[r]==-1) 53 head[r]=L[cnt]=R[cnt]=cnt; 54 else { 55 L[cnt]=L[head[r]]; 56 R[cnt]=head[r]; 57 L[R[cnt]]=R[L[cnt]]=cnt; 58 } 59 } 60 int cost[maxr]; 61 int best; 62 int micost[maxr]; 63 int cost2(){// lower_bound 64 int ret=0; 65 bool del[maxn]; 66 memset(del,false,sizeof(del)); 67 for(int c=R[0];c;c=R[c]){ 68 if(!del[c]){ 69 del[c]=true; 70 ret+=micost[c]; 71 for(int i=D[c];i!=c;i=D[i]) 72 for(int j=R[i];j!=i;j=R[j]) 73 del[col[j]]=true; 74 } 75 } 76 return ret; 77 } 78 void dance(int dep,int val){ 79 if(R[0]==0){ 80 best = min(best,val); 81 return ; 82 } 83 int c=low(); 84 if(c==0||val>=best)return ; 85 if(val+cost2()>=best)return ;// important! 86 for(int i=D[c];i!=c;i=D[i]){ 87 use[dep]=i; 88 remove(i); 89 for(int j=R[i];j!=i;j=R[j])remove(j); 90 dance(dep+1,val+cost[row[i]]); 91 for(int j=L[i];j!=i;j=L[j])resume(j); 92 resume(i); 93 } 94 } 95 96 int main(){ 97 //void data();data();return 0; 98 //freopen("in.txt","r",stdin); 99 while(~scanf("%d%d",&m,&n)){ 100 init(); 101 memset(micost,0x3f,sizeof(micost)); 102 best=0; 103 for(int i=1;i<=n;++i){ 104 int tmp,tmp2; 105 scanf("%d%d",cost+i,&tmp); 106 best+=cost[i]; 107 for(int j=0;j<tmp;++j){ 108 scanf("%d",&tmp2); 109 link(i,tmp2); 110 micost[tmp2]=min(micost[tmp2],cost[i]); 111 } 112 } 113 for(int i=1;i<=m;++i)if(!N[i]){N[1]=0;break;} 114 if(!N[1]){puts("-1");continue;} 115 dance(0,0); 116 printf("%d ",best); 117 } 118 return 0; 119 } 120 void data(){ 121 freopen("in.txt","w",stdout); 122 puts("20 100"); 123 for(int i=0;i<100;++i) 124 printf("%d %d %d ",998,1,i%20+1); 125 }
想着经过这样的优化,大概之前cf那题应该可以过吧(当时是TLE 42,然后用DP过的),改了一下,SUBMIT,AC。。。超级感动的说。。。虽然比DP的要慢,但毕竟是搜索算法嘛。。。很不错了。。。DLX 600+ms(只有第60个case>15ms....别的case都<=15ms); DP 200+ms(相对较多100+ms,200+ms)。。。这篇应该不用再编辑了吧╮(╯▽╰)╭有错漏的话请观客提出=。=本人目前处于自嗨状态

1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <string> 7 #include <vector> 8 #include <queue> 9 #include <set> 10 using namespace std; 11 12 #define ll long long 13 #define eps 1e-8 14 #define mod 21092013 15 16 #define inf 0x3f3f3f3f 17 #define maxr 110 18 #define maxn (maxr*maxr) 19 int n,m; 20 int L[maxn],R[maxn],U[maxn],D[maxn],cnt; 21 int row[maxn],col[maxn]; 22 int N[maxr],use[maxr],head[maxr]; 23 int monitor[maxr]; 24 int B; 25 void init(){ 26 memset(head,-1,sizeof(head)); 27 memset(N,0,sizeof(N)); 28 for(int i=0;i<=m;++i){ 29 L[i]=i-1,R[i]=i+1; 30 U[i]=D[i]=i; 31 row[i]=0,col[i]=i; 32 } 33 L[0]=m,R[m]=0; 34 cnt=m; 35 } 36 void remove(int x){// 删除列 37 for(int i=D[x];i!=x;i=D[i]) 38 L[R[i]]=L[i],R[L[i]]=R[i]; 39 } 40 void resume(int x){// 恢复列 41 for(int i=D[x];i!=x;i=D[i]) 42 L[R[i]]=R[L[i]]=i; 43 } 44 int low(){ 45 int mi=maxr,idx=0; 46 for(int i=R[0];i;i=R[i])if(N[i]<mi)mi=N[i],idx=i; 47 return idx; 48 } 49 void link(int r,int c){ 50 ++N[c],++cnt; 51 row[cnt]=r,col[cnt]=c; 52 U[cnt]=U[c],D[cnt]=c; 53 U[D[cnt]]=D[U[cnt]]=cnt; 54 if(head[r]==-1) 55 head[r]=L[cnt]=R[cnt]=cnt; 56 else { 57 L[cnt]=L[head[r]]; 58 R[cnt]=head[r]; 59 L[R[cnt]]=R[L[cnt]]=cnt; 60 } 61 } 62 int cost[maxr]; 63 ll best; 64 int micost[maxr]; 65 ll cost2(){// lower_bound 66 ll ret=0; 67 bool del[maxn]; 68 memset(del,false,sizeof(del)); 69 for(int c=R[0];c;c=R[c]){ 70 if(!del[c]){ 71 del[c]=true; 72 ret+=micost[c]; 73 for(int i=D[c];i!=c;i=D[i]) 74 for(int j=R[i];j!=i;j=R[j]) 75 del[col[j]]=true; 76 } 77 } 78 return ret; 79 } 80 void dance(int dep,ll val,int mak){ 81 if(R[0]==0){ 82 best = min(best,val+(ll)mak*B); 83 return ; 84 } 85 int c=low(); 86 if(c==0||val+(ll)mak*B>=best)return ; 87 if(val+(ll)mak*B+cost2()>=best)return ;// important! 88 for(int i=D[c];i!=c;i=D[i]){ 89 use[dep]=i; 90 remove(i); 91 for(int j=R[i];j!=i;j=R[j])remove(j); 92 dance(dep+1,val+cost[row[i]],max(mak,monitor[row[i]])); 93 for(int j=L[i];j!=i;j=L[j])resume(j); 94 resume(i); 95 } 96 } 97 98 int main(){ 99 //void data();data();return 0; 100 //freopen("in.txt","r",stdin); 101 while(~scanf("%d%d%d",&n,&m,&B)){ 102 init(); 103 memset(micost,0x3f,sizeof(micost)); 104 best=0;int mam=0; 105 for(int i=1;i<=n;++i){ 106 int tmp,tmp2; 107 scanf("%d%d%d",cost+i,monitor+i,&tmp); 108 best+=cost[i]; 109 mam=max(mam,monitor[i]); 110 for(int j=0;j<tmp;++j){ 111 scanf("%d",&tmp2); 112 link(i,tmp2); 113 micost[tmp2]=min(micost[tmp2],cost[i]); 114 } 115 } 116 best+=(ll)mam*B; 117 for(int i=1;i<=m;++i)if(!N[i]){N[1]=0;break;} 118 if(!N[1]){puts("-1");continue;} 119 dance(0,0,0); 120 printf("%I64d ",best); 121 } 122 return 0; 123 } 124 void data(){ 125 freopen("in.txt","w",stdout); 126 puts("20 100"); 127 for(int i=0;i<100;++i) 128 printf("%d %d %d ",998,1,i%20+1); 129 }
附上DP代码吧

1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <string> 7 #include <vector> 8 using namespace std; 9 10 #define ll long long 11 //#define inf 0x3f3f3f3f 12 #define inf (1ll<<60) 13 #define maxn 110 14 #define mod 1000000007 15 #define eps 1e-8 16 17 18 struct node{ 19 int x,k,st; 20 }p[maxn]; 21 bool cmp(node a,node b){return a.k<b.k;} 22 ll dp[1<<20]; 23 int main(){ 24 int n,m,b,mm,tmp; 25 while(~scanf("%d%d%d",&n,&m,&b)){ 26 for(int i=0;i<n;++i){ 27 scanf("%d%d%d",&p[i].x,&p[i].k,&mm); 28 p[i].st=0; 29 while(mm--){ 30 scanf("%d",&tmp); 31 p[i].st+=(1<<(tmp-1)); 32 } 33 } 34 ll ans=inf; 35 sort(p,p+n,cmp); 36 for(int j=(1<<m)-1;j;--j)dp[j]=inf; 37 dp[0]=0; 38 for(int i=0;i<n;++i){ 39 for(int j=(1<<m)-1;j>=0;--j) 40 dp[j|p[i].st] = min(dp[j|p[i].st], dp[j]+p[i].x); 41 ans = min(ans,dp[(1<<m)-1]+(ll)p[i].k*b); 42 } 43 if(ans==inf)puts("-1"); 44 else printf("%I64d ",ans); 45 } 46 return 0; 47 }