0x29 总结与练习
搜索真的菜。。困扰了很久,上个星期天没休息好导致整个礼拜没有精神。。
大概完成得七七八八了吧。真是深切的体会到暴力出奇迹的疯狂啊。
3、虫食算 从末位开始枚举判断,通过加数可以推出和的字母代表的数。那么加一个剪枝,就是通过当前所知字母对应值判断是否合法。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int n,cnt,a[30],c[30];bool bk,v[30]; char ss[3][30]; bool check(int k) { for(int i=k-1;i>=1;i--) { if(a[ss[0][i]-'A'+1]!=-1&&a[ss[1][i]-'A'+1]!=-1) { int d=a[ss[0][i]-'A'+1]+a[ss[1][i]-'A'+1]; if(a[ss[2][i]-'A'+1]!=-1) { int dd=a[ss[2][i]-'A'+1]; if(dd==d%n||dd==(d+1)%n)continue; return false; } } } return true; } void dfs(int k,int w) { if(bk==true)return ; if(cnt==n||(k==0&&c[k]==0)) { bk=true; for(int i=1;i<n;i++)printf("%d ",a[i]); printf("%d\n",a[n]); return ; } if(w==2) { int x=ss[w][k]-'A'+1; int d=a[ss[0][k]-'A'+1]+a[ss[1][k]-'A'+1]+c[k]; if(a[x]==-1) { if(v[d%n]==true)return ; a[x]=d%n;c[k-1]=d/n;v[d%n]=true;cnt++; if(check(k))dfs(k-1,0); a[x]=-1;c[k-1]=0;v[d%n]=false;cnt--; } else if(a[x]==d%n) { c[k-1]=d/n; dfs(k-1,0); c[k-1]=0; } } else { int x=ss[w][k]-'A'+1; if(a[x]==-1) { for(int i=0;i<n;i++) { if(v[i]==false) { a[x]=i;v[i]=true;cnt++; if(check(k))dfs(k,w+1); a[x]=-1;v[i]=false;cnt--; } } } else dfs(k,w+1); } } int main() { scanf("%d",&n); for(int i=0;i<3;i++)scanf("%s",ss[i]+1); memset(a,-1,sizeof(a)); memset(c,0,sizeof(c)); memset(v,false,sizeof(v)); bk=false;cnt=0;dfs(n,0); return 0; }
4、Mayan游戏 直接枚举移动方案并模拟状态的转移,hash判重就OK了。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<map> using namespace std; int n,cnt,len[10],a[10][10];bool bk; struct ansnode{int x,y,z;}as[10]; bool del[10][10]; void change(int x,int y,int z) { if(len[x+z]>=y)swap(a[x+z][y],a[x][y]); else { a[x+z][++len[x+z]]=a[x][y]; for(int i=y;i<=len[x];i++)swap(a[x][i],a[x][i+1]); a[x][len[x]]=0;len[x]--; } memset(del,false,sizeof(del)); bool qwq=true; while(qwq) { qwq=false; for(int i=1;i<=5;i++) for(int j=1;j<=len[i];j++) { if(i<=3) { if(a[i][j]==a[i+1][j]&&a[i+1][j]==a[i+2][j]) { del[i][j]=true, del[i+1][j]=true, del[i+2][j]=true; qwq=true; } } if(len[i]-j>=2) { if(a[i][j]==a[i][j+1]&&a[i][j+1]==a[i][j+2]) { del[i][j]=true, del[i][j+1]=true, del[i][j+2]=true; qwq=true; } } } for(int i=1;i<=5;i++) { int tp=0; for(int j=1;j<=len[i];j++) if(del[i][j]==false)a[i][++tp]=a[i][j]; else cnt--; for(int j=tp+1;j<=len[i];j++)a[i][j]=0; len[i]=tp; } memset(del,false,sizeof(del)); } } map<int,bool>mp; bool myhash(int k) { int d=k; for(int i=1;i<=5;i++) { for(int j=1;j<=len[i];j++)d=d*11+a[i][j]; d=d*11; } if(mp[d]==true)return true; else {mp[d]=true;return false;} } void dfs(int k) { if(bk==true)return ; if(cnt==0&&k==n+1) { for(int i=1;i<=n;i++)printf("%d %d %d\n",as[i].x-1,as[i].y-1,as[i].z); bk=true;return ; } if(cnt==0||k==n+1)return ; int tlen[10],t[10][10],tcnt; tcnt=cnt; memcpy(tlen,len,sizeof(tlen)); memcpy(t,a,sizeof(t)); for(int i=1;i<=5;i++) { for(int j=1;j<=len[i];j++) { if(i!=5) { change(i,j,1); as[k].x=i, as[k].y=j, as[k].z=1; if(!myhash(k)) dfs(k+1); as[k].x=0, as[k].y=0, as[k].z=0; cnt=tcnt; memcpy(len,tlen,sizeof(len)); memcpy(a,t,sizeof(a)); } if(i!=1) { change(i,j,-1); as[k].x=i, as[k].y=j, as[k].z=-1; if(!myhash(k)) dfs(k+1); as[k].x=0, as[k].y=0, as[k].z=0; cnt=tcnt; memcpy(len,tlen,sizeof(len)); memcpy(a,t,sizeof(a)); } } } } int main() { scanf("%d",&n); memset(len,0,sizeof(len)); for(int i=1;i<=5;i++) { while(scanf("%d",&a[i][++len[i]])!=EOF){if(a[i][len[i]]==0)break;} len[i]--;cnt+=len[i]; } bk=false;dfs(1); if(bk==false)printf("-1\n"); return 0; }
5、poj1167 (题意真星星的难理解)现在也学乖了啊,对于这种分组的题要么就是填满一组又一组要么就是一个个加,这里的话是用一个个加的(因为我一开始写的一组又一组TLE啦:)),可以暴力把所有分组方案求出,从多到少填,其中要判断因为前面选了导致现在不合法。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int n,ans,ti[110]; struct line{int st,jg,c;}l[4100];int len; bool cmp(line l1,line l2){return l1.c>l2.c;} bool check(int t,int jg) { while(t<60) { if(ti[t]==0)return false; t+=jg; } return true; } void dfs(int k,int sum,int last) { if(sum==0){ans=min(ans,k);return ;} for(int i=last;i<=len;i++) { if(k+sum/l[i].c>=ans)break; if(check(l[i].st,l[i].jg)) { for(int t=l[i].st;t<60;t+=l[i].jg)ti[t]--; dfs(k+1,sum-l[i].c,i); for(int t=l[i].st;t<60;t+=l[i].jg)ti[t]++; } } } int main() { int x; while(scanf("%d",&n)!=EOF) { memset(ti,0,sizeof(ti)); for(int i=1;i<=n;i++) scanf("%d",&x),ti[x]++; len=0; for(int st=0;st<30;st++) for(int jg=st+1;st+jg<60;jg++) if(check(st,jg)) { len++; l[len].st=st; l[len].jg=jg; l[len].c=(59-st)/jg+1; } sort(l+1,l+len+1,cmp); ans=17; dfs(0,n,1); printf("%d\n",ans); } return 0; }
6、poj3700 这里还是一个个填,有四种情况,开一个新的上升/下降区间,or加入一个以前的上升/下降区间,单论上升,假如可以加入以前的上升区间,根据贪心的思想肯定选比自己小而且最大的那个更新,更加关键的是无需尝试新开一个,这也是贪心等效性的思想。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int n,ans,c[110],slen[2],s[2][110]; bool dfs(int k) { if(slen[0]+slen[1]>=ans+1)return false; if(k==n+1)return true; int id,t; id=-1; for(int i=1;i<=slen[0];i++) { if(s[0][i]<c[k]) if(id==-1||s[0][i]>s[0][id])id=i; } if(id!=-1) { t=s[0][id];s[0][id]=c[k]; if(dfs(k+1))return true; s[0][id]=t; } else { s[0][++slen[0]]=c[k]; if(dfs(k+1))return true; s[0][slen[0]--]=0; } id=-1; for(int i=1;i<=slen[1];i++) { if(s[1][i]>c[k]) if(id==-1||s[1][i]<s[1][id])id=i; } if(id!=-1) { t=s[1][id];s[1][id]=c[k]; if(dfs(k+1))return true; s[1][id]=t; } else { s[1][++slen[1]]=c[k]; if(dfs(k+1))return true; s[1][slen[1]--]=0; } return false; } int main() { while(scanf("%d",&n)!=EOF) { if(n==0)break; for(int i=1;i<=n;i++)scanf("%d",&c[i]); slen[0]=slen[1]=0; memset(s,0,sizeof(s)); for(ans=1;;ans++) { if(dfs(1))break; } printf("%d\n",ans); } return 0; }
7、8、放到练习是侮辱智商??
9、子串变换 这题跑的挺快啊0ms,我还以为我写的这么又丑又慢会被卡,强行双向bfs,用KMP找子串相等,直接暴力转移状态,然后hash一下判重就差不多了。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<map> using namespace std; typedef long long LL; char sc[2][30],ss[2][10][30]; struct node { char sl[30];LL d; }list[2][110000];char sp[30],su[30]; map<LL,int>d[2]; int p[30]; int KMP(int w,int k,int be) { p[1]=0;int j=0,len=strlen(ss[w][k]+1); for(int i=2;i<=len;i++) { while(j>0&&ss[w][k][i]!=ss[w][k][j+1])j=p[j]; if(ss[w][k][i]==ss[w][k][j+1])j++; p[i]=j; } j=0;int splen=strlen(sp+1); for(int i=1;i<=splen;i++) { while(j>0&&sp[i]!=ss[w][k][j+1])j=p[j]; if(sp[i]==ss[w][k][j+1])j++; if(j==len&&i-len+1>be)return i-len+1; } return -1; } map<LL,bool>mp[2]; int myhash() { int sulen=strlen(su+1);LL d=0; for(int i=1;i<=sulen;i++)d=d*93LL+(LL(su[i])); return d; } int main() { scanf("%s",sc[0]+1);scanf("%s",sc[1]+1); int n=0; while(scanf("%s",ss[0][++n]+1)!=EOF){scanf("%s",ss[1][n]+1);} n--; int head[2],tail[2]; head[0]=1;tail[0]=2; memcpy(list[0][1].sl,sc[0],sizeof(list[0][1].sl)); memcpy(su,sc[0],sizeof(su)); list[0][1].d=myhash();mp[0][list[0][1].d]=true; d[0][list[0][1].d]=0; memset(su,0,sizeof(su)); head[1]=1;tail[1]=2; memcpy(list[1][1].sl,sc[1],sizeof(list[1][1].sl)); memcpy(su,sc[1],sizeof(su)); list[1][1].d=myhash();mp[1][list[1][1].d]=true; d[1][list[1][1].d]=0; memset(su,0,sizeof(su)); //--------------init---------------------- while(head[0]<tail[0]&&head[1]<tail[1]) { memcpy(sp,list[0][head[0]].sl,sizeof(sp));int splen=strlen(sp+1); LL spd=list[0][head[0]].d; if(mp[0][spd]&mp[1][spd]){printf("%d\n",d[0][spd]+d[1][spd]);return 0;} for(int i=1;i<=n&&d[0][spd]<=6;i++) { int be=KMP(0,i,0); while(be!=-1) { int len0=strlen(ss[0][i]+1),len1=strlen(ss[1][i]+1); if(splen-len0+len1>25)break; int sulen=0; for(int j=1;j<be;j++)su[++sulen]=sp[j]; for(int j=1;j<=len1;j++)su[++sulen]=ss[1][i][j]; for(int j=be+len0;j<=splen;j++)su[++sulen]=sp[j]; LL sud=myhash(); if(!mp[0][sud]) { mp[0][sud]=true;d[0][sud]=d[0][spd]+1; memcpy(list[0][tail[0]].sl,su,sizeof(list[0][tail[0]].sl)); list[0][tail[0]].d=sud; tail[0]++; } memset(su,0,sizeof(su)); be=KMP(0,i,be); } } head[0]++; memcpy(sp,list[1][head[1]].sl,sizeof(sp));splen=strlen(sp+1); spd=list[1][head[1]].d; if(mp[0][spd]&mp[1][spd]){printf("%d\n",d[0][spd]+d[1][spd]);return 0;} for(int i=1;i<=n&&d[1][spd]<=6;i++) { int be=KMP(1,i,0); while(be!=-1) { int len0=strlen(ss[0][i]+1),len1=strlen(ss[1][i]+1); if(splen-len1+len0>25)break; int sulen=0; for(int j=1;j<be;j++)su[++sulen]=sp[j]; for(int j=1;j<=len0;j++)su[++sulen]=ss[0][i][j]; for(int j=be+len1;j<=splen;j++)su[++sulen]=sp[j]; LL sud=myhash(); if(!mp[1][sud]) { mp[1][sud]=true;d[1][sud]=d[1][spd]+1; memcpy(list[1][tail[1]].sl,su,sizeof(list[1][tail[1]].sl)); list[1][tail[1]].d=sud; tail[1]++; } memset(su,0,sizeof(su)); be=KMP(1,i,be); } } head[1]++; } printf("NO ANSWER!\n"); return 0; }
10、poj2044 二进制表示状态,记录四个角落多久没降雨,判重即可。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int Bin[30]; const int dx[9]={0,-2,-1,0,0,1,2,0,0}; const int dy[9]={0,0,0,-2,-1,0,0,1,2}; int n,u[410]; bool v[370][9][7][7][7][7]; int point(int x,int y){return (x-1)*4+y;} bool check(int k,int x,int y) { int zt=0; zt^=Bin[point(x,y)]; zt^=Bin[point(x+1,y)]; zt^=Bin[point(x,y+1)]; zt^=Bin[point(x+1,y+1)]; return (0<x)&&(x<=3)&&(0<y)&&(y<=3)&&(!(zt&u[k])); } int dfs(int k,int x,int y,int rain[4]) { if(k==n+1)return 1; if(v[k][point(x,y)][rain[0]][rain[1]][rain[2]][rain[3]])return 0; v[k][point(x,y)][rain[0]][rain[1]][rain[2]][rain[3]]=true; for(int i=0;i<=8;i++) { int tx=x+dx[i],ty=y+dy[i]; int train[4];memcpy(train,rain,sizeof(train)); for(int j=0;j<=3;j++)train[j]++; if(tx==1&&ty==1)train[0]=0; if(tx==3&&ty==1)train[1]=0; if(tx==1&&ty==3)train[2]=0; if(tx==3&&ty==3)train[3]=0; if(check(k,tx,ty)&&train[0]<=6&&train[1]<=6&&train[2]<=6&&train[3]<=6) { if(dfs(k+1,tx,ty,train))return 1; } if(k==1)break; } return 0; } int main() { Bin[1]=1;for(int i=2;i<=20;i++)Bin[i]=Bin[i-1]*2; while(scanf("%d",&n)!=EOF) { if(n==0)break; for(int i=1;i<=n;i++) { u[i]=0;int x; for(int j=1;j<=16;j++) { scanf("%d",&x); if(x==1)u[i]^=Bin[j]; } } memset(v,false,sizeof(v)); int rain[4];memset(rain,0,sizeof(rain)); printf("%d\n",dfs(1,2,2,rain)); } return 0; }
11、留坑
12、poj1945 这题真的是很奇淫了,较小数不能超过100?gc控到50都没问题
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,c; }list[1100000];int head,tail; bool mp[110][410000]; void insert(int x,int y,int c) { if(x>y)swap(x,y); if(y>400000||x>100||x<0||mp[x][y])return ; mp[x][y]=true; list[tail].x=x,list[tail].y=y,list[tail].c=c; tail++;if(tail==1050000)tail=1; } int main() { int k; scanf("%d",&k); head=1,tail=2; list[head].x=0,list[head].y=1,list[head].c=0; mp[0][1]=true; while(head!=tail) { int x=list[head].x,y=list[head].y,c=list[head].c; if(x== k||y==k){printf("%d\n",c);break;} insert(x,x+y,c+1), insert(y,x+y,c+1); insert(y-x,y,c+1), insert(y-x,x,c+1); insert(x*2,y,c+1), insert(x,y*2,c+1); insert(x,x*2,c+1), insert(y,y*2,c+1); head++;if(head==1050000)head=1; } return 0; }
13、poj4007 迭代加深,暴力dfs+bfs找被覆盖的点,当时我满脑子的都是神之折纸的个游戏啊,怎么IDA*,我玩的时候看到步数比颜色少就重来,但是这个故意卡好像。。结果gc%了一发就是这么搞?真是。。。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int dx[4]={-1,0,1,0}; const int dy[4]={0,-1,0,1}; int n,cnt,a[10][10]; int xx[110],yy[110];bool v[10][10]; bool check(int x,int y,int c){return 0<x&&x<=n&&0<y&&y<=n&&a[x][y]==c;} int bfs(int c) { int head=1,tail=2,cg=0;xx[1]=1,yy[1]=1; memset(v,false,sizeof(v));v[1][1]=true; while(head<tail) { int x=xx[head],y=yy[head]; for(int i=0;i<=3;i++) { int tx=x+dx[i],ty=y+dy[i]; if((check(tx,ty,c)||a[tx][ty]==-1)&&v[tx][ty]==false) { if(a[tx][ty]!=-1)cg++; v[tx][ty]=true;a[tx][ty]=-1; xx[tail]=tx;yy[tail]=ty; tail++; } } head++; } return cg; } bool bb[10]; int count() { memset(bb,false,sizeof(bb)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(a[i][j]!=-1)bb[a[i][j]]=true; int c=0; for(int i=0;i<=5;i++) if(bb[i]==true)c++; return c; } int ans; bool dfs(int k) { if(k+count()>ans)return false; if(cnt==0)return true; int t[10][10]; for(int c=0;c<=5;c++) { memcpy(t,a,sizeof(t)); int d=bfs(c); if(d>0) { cnt-=d; if(dfs(k+1))return true; cnt+=d; } memcpy(a,t,sizeof(a)); } return false; } int main() { while(scanf("%d",&n)!=EOF) { if(n==0)break; cnt=n*n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); int c=a[1][1]; cnt--;a[1][1]=-1; cnt-=bfs(c); if(cnt==0)printf("0\n"); else { for(ans=1;;ans++) { if(dfs(0))break; } printf("%d\n",ans); } } return 0; }
pain and happy in the cruel world.