较复杂搜索,剪枝
1.hdu1429
思路:
把这10把钥匙当成每一个为,要要1<<10个位保存所有的状态,
然后就是模拟捡起钥匙,捡起钥匙就是说明这个位上的数字变成1这个状态,
只要|一下就好了,然后改变在这个点的状态。。。。模拟碰到门的情况,
那么就和这个位置上的位&一次,看是1还是0,1代表已经捡到了这把钥匙,可以开门
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #define N 30 using namespace std; char map[N][N],str[N];; int n,m,t; bool vis[N][N][(1<<11)]; int dx[]= {-1,1,0,0}; int dy[]= {0,0,-1,1}; struct node { int x,y,step,key; }st; queue<node>Q; bool check(int x,int y) { if(x>=1&&x<=n&&y>=1&&y<=m&&map[x][y]!='*') return true; return false; } int bfs() { while(!Q.empty()) Q.pop(); memset(vis,false,sizeof(vis)); vis[st.x][st.y][st.key]=true; st.key=st.step=0;Q.push(st); node cur,nex; while(!Q.empty()) { cur=Q.front();Q.pop(); if(map[cur.x][cur.y]=='^')return cur.step; for(int i=0; i<4; i++) { nex.x=cur.x+dx[i];nex.y=cur.y+dy[i]; nex.key=cur.key; if(!check(nex.x,nex.y)) continue; nex.step=cur.step+1; if(nex.step>=t) continue; else if(map[nex.x][nex.y]>='A' && map[nex.x][nex.y]<='Z') { int temp=map[nex.x][nex.y]-'A'; int K=cur.key&1<<temp; if(K && !vis[nex.x][nex.y][nex.key]) { vis[nex.x][nex.y][nex.key]=true; Q.push(nex); } } else if(map[nex.x][nex.y]>='a' && map[nex.x][nex.y]<='z') { int temp=map[nex.x][nex.y]-'a'; nex.key=cur.key|1<<temp; if(!vis[nex.x][nex.y][nex.key]) { vis[nex.x][nex.y][nex.key]=true; Q.push(nex); } } else { if(!vis[nex.x][nex.y][nex.key]) { vis[nex.x][nex.y][nex.key]=true; Q.push(nex); } } } }return -1; } inline void init() { for(int i=1;i<=n;i++) { scanf("%s",str+1); for(int j=1;j<=m;j++) { if(str[j]=='@') { st.x=i;st.y=j; map[i][j]=str[j]; } else map[i][j]=str[j]; } } } int main() { while(~scanf("%d%d%d",&n,&m,&t)) { init(); int ans=bfs(); printf("%d\n",ans); } return 0; }
2.洛谷1731
思路:
①要是剩下体积除以最大(虽然取不到)半径所得到的表面积+累计表面积大于答案退出
② 要是剩下来的体积已经小于该层最小体积了就退出
③ 还有 为了剪枝,我们要起先预处理某一层的最大不可的表面积和体积
#include<cstdio> #include<cmath> #include<algorithm> #define maxn 17 using namespace std; int NN,M,N,ans; int ss[maxn],sv[maxn]; void dfs(int t,int S,int V,int lR,int lH)//层数,已用总面积,已用总体积,上一层半径 ,上一层高度 { if (t==0) { if (V==N) ans=min(ans,S); return ; } if (V+sv[t]>N) return; if (S+ss[t]>ans) return; if (S+2*(N-V)/lR>ans) return; for (int r=lR-1;r>=t;r--) { if (t==M) S=r*r; int maxh=min((N-V-sv[t-1])/(r*r),lH-1); for (int h=maxh;h>=t;h--) dfs(t-1,S+2*r*h,V+r*r*h,r,h); } } int main() { scanf("%d%d",&N,&M); for (int i=1;i<=M;i++) { ss[i]=2*i*i;ss[i]+=ss[i-1]; sv[i]=i*i*i;sv[i]+=sv[i-1]; }ans=0x3f3f3f3f; dfs(M,0,0,sqrt(N),N); if (ans==0x3f3f3f3f) printf("0"); else printf("%d\n",ans); return 0; }
3.虫食算
思路:
嗯...倒着搜,一列一列的搜
边搜边剪枝。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define N 27 using namespace std; int n,m,ans,cnt,tmp; char s1[N],s2[N],s3[N]; int match[N]; bool vis[N]; void dfs(int use,bool flag=false) { if(use==n) { if(!flag) { for(int i=0;i<n;i++) printf("%d ",match[i]); exit(0); } else return; } for(int k=n-2-use;k>=0;k--) if(match[s1[k]]!=-1 && match[s2[k]]!=-1 && match[s3[k]]!=-1 && (match[s1[k]]+match[s2[k]])%n!=match[s3[k]] && (1+match[s1[k]]+match[s2[k]])%n!=match[s3[k]]) return; int tmp=n-1-use; if(match[s1[tmp]]==-1) { for(int k=n-1;k>=0;k--) { if(!vis[k]) { vis[k]=1;match[s1[tmp]]=k; dfs(use,flag); vis[k]=0;match[s1[tmp]]=-1; } } } else if(match[s2[tmp]]==-1) { for(int k=n-1;k>=0;k--) { if(!vis[k]) { vis[k]=1;match[s2[tmp]]=k; dfs(use,flag); vis[k]=0;match[s2[tmp]]=-1; } } } else if(match[s3[tmp]]==-1) { int pre=match[s1[tmp]]+match[s2[tmp]]+flag; for(int k=0;k<n;k++) if(match[k]==pre%n) return; match[s3[tmp]]=pre%n; vis[match[s3[tmp]]]=1; dfs(use+1,pre>=n); vis[match[s3[tmp]]]=0; match[s3[tmp]]=-1; } else { int pre=match[s1[tmp]]+match[s2[tmp]]+flag; if(match[s3[tmp]]==pre%n) dfs(use+1,pre>=n); } } int main() { scanf("%d%s%s%s",&n,s1,s2,s3); for(int i=0;i<n;i++) { match[i]=-1; s1[i]-='A';s2[i]-='A';s3[i]-='A'; }dfs(0); return 0; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。