A - 棋盘问题
题意
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
解法:n皇后的变形,注意放的位置不一定,并不是每一行都要放,计个step,然后dfs每一个点时,记得回溯上去处理一下,把vis[i]置为0,step--即可,然后处理完此次结束后,dfs(x+1),处理下一位;
#include<cstdio> #include<cstring> using namespace std; #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) int step,ans,n,k; char mp[20][20]; bool vis[20]; void dfs(int x){ if(step==k){ ans++; return ; } if(x>=n)return ; for(int i=0;i<n;i++){ if(!vis[i]&&mp[x][i]=='#'){ step++; vis[i]=1; dfs(x+1); vis[i]=0; step--; } } dfs(x+1); } int main(){ while(~scanf("%d %d",&n,&k)){ memset(vis,0,sizeof vis); if(n+k<0)break; rep(i,0,n-1){ scanf("%s",mp[i]); } ans=step=0; dfs(0); printf("%d ",ans); } return 0; }
B - Dungeon Master
题意:就是个三维迷宫,直接广搜即可,用一个方向数组
#include<bits/stdc++.h> #include<queue> #include<cstring> using namespace std; #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) #define pb push_back #define fi first #define se second typedef long long ll; typedef unsigned long long ull; typedef long double ldb; const int maxn=1e5+5; bool isprime[maxn]; void makeprime(){ memset(isprime,true,sizeof isprime); isprime[1]=0; for(int i=2;i*i<=maxn;i++){ if(isprime[i]==0)continue; for(int j=i*2;j<=maxn;j+=i){ isprime[j]=0; } } // rep(i,1,maxn){ // cout<<i<<" "<<isprime[i]<<endl; // } } struct point{int num,step;}; int ans,p,q; bool vis[maxn]; bool bfs(){ memset(vis,0,sizeof vis); vis[p]=1; point tmp,next; tmp.num=p,tmp.step=0; queue<point>Q; Q.push(tmp); while(!Q.empty()){ tmp=Q.front(); Q.pop(); vis[tmp.num]=1; if(tmp.num==q){ ans=tmp.step; return true; } int t=tmp.num; for(int i=0;i<4;i++){ for(int j=0;j<=9;j++){ t=tmp.num; if(i==0){ t-=t%10; t+=j; } else if(i==1){ t-=t%100/10*10; t+=j*10; } else if(i==2){ t-=t%1000/100*100; t+=j*100; } else if(i==3){ t-=t%10000/1000*1000; t+=j*1000; } if(t==tmp.num||t<1000||vis[t]||!isprime[t])continue; next.num=t,next.step=tmp.step+1; vis[t]=1; Q.push(next); } } } return false; } int main(){ makeprime(); int cas; scanf("%d",&cas); while(cas--){ memset(vis,0,sizeof vis); scanf("%d %d",&p,&q); ans=0; if(bfs())printf("%d ",ans); else printf("Impossible "); } return 0; }
题意:给你n和m,问几步能走到,直接广搜即可
#include<cstdio> #include<queue> #include<cstring> using namespace std; #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) #define pb push_back #define fi first #define se second #define check(x) (x<=N&&x>=0) typedef long long ll; typedef unsigned long long ull; typedef long double ldb; const int N=1e5+5; bool vis[N]; int step[N]; int n,k; void bfs(){ queue<int>Q; vis[n]=1; step[n]=0; Q.push(n); while(!Q.empty()){ int s=Q.front(); if(s==k)return ; Q.pop(); if(check(s+1)&&!vis[s+1]){ vis[s+1]=1; step[s+1]=step[s]+1; Q.push(s+1); } if(check(s-1)&&!vis[s-1]){ vis[s-1]=1; step[s-1]=step[s]+1; Q.push(s-1); } if(check(s<<1)&&!vis[s<<1]){ vis[s<<1]=1; step[s<<1]=step[s]+1; Q.push(s<<1); } } } int main(){ while(~scanf("%d%d",&n,&k)){ if(n>=k){ printf("%d ",n-k); } else { memset(vis,false,sizeof vis); memset(step,0,sizeof step); bfs(); printf("%d ",step[k]); } } return 0; }
D - Fliptile(学到许多)
POJ - 3279题意: 给你一个01网格图,问你怎么按这些点,使得网格图全部置为0,找出字典序最小的方案;
解法: 这题用到二进制思想,解法就是枚举第一行的按键,然后剩下的每一行都可以由上一行递推而来;
递推公式为:press[i][j]=(mp[i-1][j]+press[i-1][j]+press[i-1][j+1]+press[i-2][j]+press[i-1][j-1])&1;
最后判断一下情况是否符合,即最后一行按键是否能全部熄灭,
这里我犯了一个错误,就是判断最后一行时没有按照递推公式算导致错误;
然后枚举第一行的按键用到了二进制,即枚举0<i<(1<<m),表示有m位二进制数,然后用位运算截取每一位数,即为 press[1][j]=(i>>(m-j))&1;
over
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int mp[20][20],ans[20][20],press[20][20]; int n,m; const int inf=0x3f3f3f3f; int guess(){ for(int i=2;i<=n;i++){ for(int j=1;j<=m;j++){ press[i][j]=(mp[i-1][j]+press[i-1][j]+press[i-1][j+1]+press[i-2][j]+press[i-1][j-1])&1; } } for(int j=1;j<=m;j++){ if((press[n][j]+mp[n][j]+ press[n-1][j]+press[n][j-1]+press[n][j+1])&1!=0) return inf; } int cnt=0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cnt+=press[i][j]; } } return cnt; } int main(){ while(~scanf("%d%d",&n,&m)){ memset(mp,0,sizeof mp); memset(ans,0,sizeof ans); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&mp[i][j]); int res=inf; for(int i=0;i<(1<<m);i++){ memset(press,0,sizeof press); int test=1; for(int j=1;j<=m;j++){ press[1][j]=(i>>(m-j))&1; } // cout<<"test:"<<i<<" "<<guess()<<endl; // for(int i=1;i<=n;i++) // for(int j=1;j<=m;j++) // printf("%d%c",press[i][j],j==m?' ':' '); int sum=guess(); if(res>sum){ res=sum; memcpy(ans,press,sizeof press); } } if(res==inf)printf("IMPOSSIBLE "); else { // cout<<"test:"<<endl; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) printf("%d%c",ans[i][j],j==m?' ':' '); } } return 0; }
E - Find The Multiple
题意:就是给你一个数,让你找它的一个只含01倍数的十进制数,
解法:直接深搜,但开始T了一发,没有做好剪树枝
计一个flag,如果搜到目标就停止;这样就能过了;
#include<cstdio> using namespace std; #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) #define pb push_back typedef long long ll; typedef unsigned long long ull; int n,flag; ull ans; void dfs(ull x,int step){ if(flag)return ; if(x%n==0){ flag=1; ans=x; return ; } if(step==19)return ; dfs(x*10+1,step+1); dfs(x*10,step+1); } int main(){ // cout<<1000000000000000110%6<<endl; while(~scanf("%d",&n),n){ ans=0,flag=0; dfs(1*1ll,1); printf("%lld ",ans); } return 0; }
F - Prime Path
题意:就是给你两个素数,问你移动几步,使得由p走到q,而且每次移动只能变为素数,问你要变换几步;
解法:直接广搜即可;注意枚举每一位的情况;
#include<bits/stdc++.h> #include<queue> #include<cstring> using namespace std; #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) #define pb push_back #define fi first #define se second typedef long long ll; typedef unsigned long long ull; typedef long double ldb; const int maxn=1e5+5; bool isprime[maxn]; void makeprime(){ memset(isprime,true,sizeof isprime); isprime[1]=0; for(int i=2;i*i<=maxn;i++){ if(isprime[i]==0)continue; for(int j=i*2;j<=maxn;j+=i){ isprime[j]=0; } } // rep(i,1,maxn){ // cout<<i<<" "<<isprime[i]<<endl; // } } struct point{int num,step;}; int ans,p,q; bool vis[maxn]; bool bfs(){ memset(vis,0,sizeof vis); vis[p]=1; point tmp,next; tmp.num=p,tmp.step=0; queue<point>Q; Q.push(tmp); while(!Q.empty()){ tmp=Q.front(); Q.pop(); vis[tmp.num]=1; if(tmp.num==q){ ans=tmp.step; return true; } int t=tmp.num; for(int i=0;i<4;i++){ for(int j=0;j<=9;j++){ t=tmp.num; if(i==0){ t-=t%10; t+=j; } else if(i==1){ t-=t%100/10*10; t+=j*10; } else if(i==2){ t-=t%1000/100*100; t+=j*100; } else if(i==3){ t-=t%10000/1000*1000; t+=j*1000; } if(t==tmp.num||t<1000||vis[t]||!isprime[t])continue; next.num=t,next.step=tmp.step+1; vis[t]=1; Q.push(next); } } } return false; } int main(){ makeprime(); int cas; scanf("%d",&cas); while(cas--){ memset(vis,0,sizeof vis); scanf("%d %d",&p,&q); ans=0; if(bfs())printf("%d ",ans); else printf("Impossible "); } return 0; }
G - Shuffle'm Up
题意:就是给你两堆牌,问你怎么洗才能洗到目标状态,如果洗不到,输出-1;
解法:模拟洗牌的过程,如果洗到初始的状态,说明洗不到,
这里我犯了一个错误,就是在在下标里面写位运算会出错,也不知tmp[i*2]=s2[i];道为什么;
tmp[i*2]=s2[i]; 写成tmp【i>.>1】就不对了
#include<iostream> #include<string> #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) using namespace std; typedef long long ll; string tmp,s1,s2,s12,goal; int step,n,ans; void bfs(){ s1=tmp.substr(0,n); s2=tmp.substr(n,n); for(int i=0;i<n;i++){ tmp[i*2]=s2[i]; tmp[i*2+1]=s1[i]; } step++; if(tmp.compare(goal)==0){ ans=step; return ; } if(tmp.compare(s12)==0){ ans=-1; return ; } bfs(); } int main(){ int t,cas=1; // scanf("%d",&t); cin>>t; while(t--){ // scanf("%d",&n); cin>>n>>s1>>s2>>goal; tmp=s1+s2; s12=tmp; ans=step=0; bfs(); printf("%d %d ",cas++,ans); } return 0; }
待更新;
PS:还是太菜了,要坚持刷题,写博客;