0x21 剪枝
这一章真是心态崩,剪枝太玄学啦,特别是那个搜索顺序我靠真的。。。
poj1011 枚举答案,搜索记录当前到第几根木棒。 剪枝:1、从大到小排序 2、排除等效,这个感觉还行,就是木棒按大小顺序进去,去除顺序不同的相同的情况,相同的木棒也是不用管的。 好的前面这些都可以想,关键是第三个,拼接第一个失败就全部重来。这个真是没想到
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int n,L,C,c[110]; bool cmp(int x,int y){return x>y;} bool v[110]; bool dfs(int k,int len,int last) { if(k==C+1)return true; if(len==L)return dfs(k+1,0,0); int fail=0; for(int i=last+1;i<=n;i++) { if(v[i]==false&&len+c[i]<=L&&c[i]!=fail) { v[i]=true; if(dfs(k,len+c[i],i))return true; v[i]=false; fail=c[i]; if(len==0)return false; } } return false; } int main() { while(scanf("%d",&n)!=EOF) { if(n==0)break; int sum=0; for(int i=1;i<=n;i++) scanf("%d",&c[i]), sum+=c[i]; sort(c+1,c+n+1,cmp); int mmin=2147483647; for(int i=1;i*i<=sum;i++) if(sum%i==0) { if(i<mmin) { L=i, C=sum/i; memset(v,false,sizeof(v)); if(dfs(1,0,0)==true)mmin=min(mmin,i); } if(sum/i<mmin&&i*i!=sum) { L=sum/i, C=i; memset(v,false,sizeof(v)); if(dfs(1,0,0)==true)mmin=min(mmin,sum/i); } } printf("%d\n",mmin); } return 0; }
poj1190 这题简直就是剪枝的代表作了。。。我可以算是想出了1.5+2??个trick,但是这题整整五个剪枝啊!!!
1、大小,看到这个我都快条件反射了,管他有的没的倒序就是没错的
2、上下界,这个我想得还要复杂一点,导致有点难算,lyd就很暴力了直接开根
3、4、对于体积和表面积,到达目标的最小花费+当前花费比限制、当前最小花费大,那么就剪掉。我纠结了一会为啥一个叫可行性剪枝一个叫最优性剪枝,是因为体积是确定的而表面积是要求的
5、最***玄学的就是这个不等式了,上面全部的体积可以表示成sigema(1~dep-1)h[i]*r[i]^2,表面积就是2*sigema(1~dep-1)h[i]*r[i], 假设当前已经的体积为V
2*sigema(1~dep-1)h[i]*r[i] = 2/r[dep]*sigema(1~dep-1)h[i]*r[i]*r[dep] >= 2/r[dep]*sigema(1~dep-1)h[i]*r[i]*r[i] = 2*(N-V)/r[dep] 这个时候又可以判表面积。。。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int N,m,mmin,r[11000],h[11000]; int minV[30],minS[30]; void dfs(int k,int V,int S) { if(minV[k]+V>N)return ; if(minS[k]+S>mmin)return ; if(2*(N-V)/r[k+1]+S>mmin)return ; if(k==0) { if(minV[k]+V==N)mmin=min(mmin,S); return ; } int Rli=min( int(sqrt(double(N-V+1))) , r[k+1]-1 ); for(int R=Rli;R>=k;R--) { int Hli=min( (N-V)/(R*R) , h[k+1]-1 ); for(int H=Hli;H>=k;H--) { r[k]=R;h[k]=H; dfs(k-1,V+R*R*H,S+2*R*H+((k==m)?R*R:0)); } } } int main() { scanf("%d%d",&N,&m); for(int i=1;i<=m;i++) minV[i]=i*i*i+minV[i-1], minS[i]=2*i*i+minS[i-1]; mmin=2147483647; r[m+1]=h[m+1]=2147483647; dfs(m,0,0); printf("%d\n",mmin); return 0; }
poj3076 状压,判点,判字母,绝望,留坟
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<bitset> using namespace std; int cnt; char ss[20][20],sc[310][20][20]; bitset<16>mp[20][20],tt[310][20][20],ts[310][20][20]; void init() { memset(mp,0,sizeof(mp)); for(int j=1;j<=16;j++)//行 { int zt=0; for(int i=1;i<=16;i++) if(ss[i][j]!='-') zt|=(1<<(ss[i][j]-'A')); for(int i=1;i<=16;i++) mp[i][j]|=zt; } for(int i=1;i<=16;i++)//列 { int zt=0; for(int j=1;j<=16;j++) if(ss[i][j]!='-') zt|=(1<<(ss[i][j]-'A')); for(int j=1;j<=16;j++) mp[i][j]|=zt; } for(int i=1;i<=16;i+=4) for(int j=1;j<=16;j+=4) { int zt=0; for(int k=1;k<=4;k++) for(int l=1;l<=4;l++) if(ss[i+k-1][j+l-1]!='-') zt|=(1<<(ss[i+k-1][j+l-1]-'A')); for(int k=1;k<=4;k++) for(int l=1;l<=4;l++) mp[i+k-1][j+l-1]|=zt; } cnt=0; for(int i=1;i<=16;i++) for(int j=1;j<=16;j++) { if(ss[i][j]=='-')cnt++; mp[i][j].flip(); } } bitset<16>p;bool v[16]; bool check() { for(int i=1;i<=16;i++) for(int j=1;j<=16;j++) if(mp[i][j]==0&&ss[i][j]=='-')return false; for(int i=1;i<=16;i++) { p.reset();memset(v,false,sizeof(v)); for(int j=1;j<=16;j++) { if(ss[i][j]!='-')v[ss[i][j]-'A']=true; else p|=mp[i][j]; } for(int o=0;o<=15;o++) if(p[o]==0&&v[o]==false)return false; } for(int j=1;j<=16;j++) { p.reset(); for(int i=1;i<=16;i++) { if(ss[i][j]!='-')v[ss[i][j]-'A']=true; else p|=mp[i][j]; } for(int o=0;o<=15;o++) if(p[o]==0&&v[o]==false)return false; } for(int i=1;i<=16;i+=4) for(int j=1;j<=16;j+=4) { p.reset();memset(v,false,sizeof(v)); for(int k=1;k<=4;k++) for(int l=1;l<=4;l++) { if(ss[i+k-1][j+l-1]!='-')v[ss[i+k-1][j+l-1]-'A']=true; else p|=mp[i+k-1][j+l-1]; } for(int o=0;o<=15;o++) if(p[o]==0&&v[o]==false)return false; } return true; } void influence(int x,int y) { int o=ss[x][y]-'A'; for(int j=1;j<=16;j++)mp[x][j][o]=0; for(int i=1;i<=16;i++)mp[i][y][o]=0; int i=((x-1)/4)*4+1,j=((y-1)/4)*4+1; for(int k=1;k<=4;k++) for(int l=1;l<=4;l++) mp[i+k-1][j+l-1][o]=0; } bool bk; void dfs(int k,int dep) { if(bk==true)return ; memcpy(ts[dep],mp,sizeof(ts[dep])); memcpy(sc[dep],ss,sizeof(sc[dep])); bool qwq=true; while(qwq) { qwq=false; for(int i=1;i<=16;i++) for(int j=1;j<=16;j++) { if(ss[i][j]=='-'&&mp[i][j].count()==1) { k--;qwq=true; for(int o=0;o<=15;o++) if(mp[i][j][o]==1) { ss[i][j]='A'+o; influence(i,j); break; } } } for(int o=1;o<=16;o++) { for(int i=1;i<=16;i++) { int u=0,jj; for(int j=1;j<=16;j++) if(mp[i][j][o]==1) { u++;jj=j; if(u==2)break; } if(u==1) { ss[i][jj]='A'+o; influence(i,jj); } } for(int j=1;j<=16;j++) { int u=0,ii; for(int i=1;i<=16;i++) if(mp[i][j][o]==1) { u++;ii=i; if(u==2)break; } if(u==1) { ss[ii][j]='A'+o; influence(ii,j); } } for(int i=1;i<=16;i+=4) for(int j=1;j<=16;j+=4) { int u=0,ii,jj; for(int k=1;k<=4;k++) for(int l=1;l<=4;l++) { if(mp[i+k-1][j+l-1][o]==1) { u++;ii=i;jj=j; if(u==2)break; } } if(u==1) { ss[ii][jj]='A'+o; influence(ii,jj); } } } }//必定赋值 if(!check()) { memcpy(mp,ts[dep],sizeof(mp)); memcpy(ss,sc[dep],sizeof(ss)); return ; } if(k==0) { bk=true; for(int i=1;i<=16;i++) { for(int j=1;j<=16;j++)printf("%c",ss[i][j]); printf("\n"); } return ; } int cc=999999,nx,ny; for(int i=1;i<=16;i++) for(int j=1;j<=16;j++) if(ss[i][j]=='-'&&mp[i][j].count()<cc) { cc=mp[i][j].count(); nx=i,ny=j; } for(int o=0;o<=15;o++) if(mp[nx][ny][o]==1) { memcpy(tt[dep],mp,sizeof(tt[dep])); ss[nx][ny]='A'+o; influence(nx,ny); if(check()) dfs(k-1,dep+1); ss[nx][ny]='-'; memcpy(mp,tt[dep],sizeof(mp)); } memcpy(mp,ts[dep],sizeof(mp)); memcpy(ss,sc[dep],sizeof(ss)); } int main() { for(int i=1;i<=16;i++)scanf("%s",ss[i]+1); init(); bk=false;dfs(cnt,1); return 0; }
pain and happy in the cruel world.