搜索复习-基础水题(一共12道)
由于是跟着黄学长刷题,此篇博文里所有JudgeOnline都是http://218.5.5.242:9018/JudgeOnline/
tyvj1080 N皇后
描述
列号
1 2 3 4 5 6
-------------------------
1 | | O | | | | |
-------------------------
2 | | | | O | | |
-------------------------
3 | | | | | | O |
-------------------------
4 | O | | | | | |
-------------------------
5 | | | O | | | |
-------------------------
6 | | | | | O | |
-------------------------
上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。
特别注意: 对于更大的N(棋盘大小N x N)你的程序应当改进得更有效。不要事先计算出所有解然后只输出(或是找到一个关于它的公式),这是作弊。如果你坚持作弊,那么你登陆tyvj的帐号将被无警告删除
输入格式
输出格式
测试样例1
输入
6
输出
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=15; int n,tot,ans[maxn]; bool l[maxn],jia[maxn*2],jian[maxn*2]; void p() { for(int i=1;i<=n;++i) printf("%d ",ans[i]); printf("\n"); } void s(int pos) { if(pos==n+1) { if((++tot)<=3) p(); return ; } for(int i=1;i<=n;++i) { if(l[i]||jia[pos+i]||jian[pos-i+n]) continue; l[i]=jia[pos+i]=jian[pos-i+n]=1; ans[pos]=i;s(pos+1); l[i]=jia[pos+i]=jian[pos-i+n]=0; } } int main() { cin>>n; s(1); cout<<tot; return 0; }
codevs2080 特殊的质数肋骨
农民约翰的母牛总是产生最好的肋骨。 你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们。 农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还剩下的肋骨上的数字都组成一个质数,举例来说: 7 3 3 1 全部肋骨上的数字 7331是质数;三根肋骨 733是质数;二根肋骨 73 是质数;当然,最后一根肋骨 7 也是质数。 7331 被叫做长度 4 的特殊质数。 写一个程序对给定的肋骨的数目 N(1<=N<=8),求出所有的特殊质数。 数字1不被看作一个质数。
单独的一行包含N。
按顺序输出长度为 N 的特殊质数,每行一个。
4
2333 2339 2393 2399 2939 3119 3137 3733 3739 3793 3797 5939 7193 7331 7333 7393
再来一发
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=10; int n,ans[maxn]; bool ok(int x) { if(x==1) return 0; int y=sqrt(x); for(int i=2;i<=y;++i) if(x%i==0) return 0; return 1; } void s(int pos,long long x) { if(!ok(x)) return; if(pos==n+1) { printf("%lld\n",x); return; } for(int i=1;i<=9;++i) { ans[pos]=i;s(pos+1,x*10+i); } } int main() { cin>>n; s(1,0); return 0; }
RQNOJ67 选数
已知 n 个整数 x1,x2,…,xn,以及一个整数 k(k<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当 n=4,k=3,4 个整数分别为 3,7,12,19 时,可得全部的组合与它们的和为:
3+7+12=22 3+7+19=29 7+12+19=38 3+12+19=34。
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=29)。
键盘输入,格式为:
n , k (1<=n<=20,k<n)
x1,x2,…,xn (1<=xi<=5000000)
屏幕输出,格式为:
一个整数(满足条件的种数)。
4 3
3 7 12 19
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=20+5; int n,k,a[maxn],tot; bool ok(int x) { if(x<=1) return 0; int y=sqrt(x); for(int i=2;i<=y;++i) if(x%i==0) return 0; return 1; } void s(int pos,int f,int x) { if(f==k) { if(ok(x)) tot++; return; } if(pos>n) return; s(pos+1,f,x); s(pos+1,f+1,x+a[pos]); } int main() { cin>>n>>k; for(int i=1;i<=n;++i) cin>>a[i]; s(1,0,0); cout<<tot; return 0; }
codevs1116 四色问题
题目描述
4色问题:对平面或球面的任何一幅地图,只需要使用4种颜色就可以给地图上的每个国家填色,使得任意2个有一段公共边界的国家所填的颜色是不同的。
输入
用邻接矩阵表示地图。读入格式如下:
N(有N个国家,N不超过20)
N行用空格隔开的0/1串(1表示相邻,0表示不相邻)
输出
最多的填色方案
样例输入
0 0 0 1 0 0 1 0
0 0 0 0 0 1 0 1
0 0 0 0 0 0 1 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0
1 0 1 0 0 0 0 0
0 1 0 0 0 0 0 0
样例输出
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=20+5; int n,cl[maxn],ans; bool tu[maxn][maxn]; int get_f(int pos) { int x=15; for(int i=1;i<pos;++i) if(tu[i][pos])x-=(x&(1<<(cl[i]-1))); return x; } void s(int pos) { if(pos>n) { ans++; return; } int x=get_f(pos); for(int i=1;i<=4;++i) if(x&(1<<(i-1))) { cl[pos]=i; s(pos+1); } } int main() { cin>>n; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) cin>>tu[i][j]; s(1); cout<<ans; return 0; }
JudgeOnline1427 寻找国都名
题目描述
给出一个字符矩阵及要寻找的国都名,要求从这个矩阵中找到这个国都名,并输出这个国都名的起始位置及搜索的方向。搜索可沿8个方向进行,见下图:
输入
第一行有一个整数M和N(1<=M,N<=10),表示该字符矩阵的长和宽。接下来就是M*N的字符矩阵。接下来一行是一串字符,代表要寻找的国都名。
输出
样例输入
8 8 okdublin alpgocev rasmusmb oslondon yibdglrc krzurich oaibxmuz tpqglamv dublin
样例输出
1 3 11111
字符串的读入要小心了,或许坑人的什么都有。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=10+5,maxlen=10000+10; int n,m,len,ans[maxlen],st[3]; char s[maxn][maxn],cc,nme[maxlen]; bool ok; int f[10][2]; void p() { ok=1; printf("%d %d\n",st[0],st[1]); for(int i=1;i<len;++i) cout<<ans[i]; } void dfs(int x,int y,int pos) { if(s[x][y]!=nme[pos]||ok) return; if(pos==len) p(); int xx,yy; for(int i=1;i<=8&&!ok;++i) { xx=x+f[i][0];yy=y+f[i][1]; if(!xx||!yy||xx>n||yy>m) continue; ans[pos]=i;dfs(xx,yy,pos+1); } } int main() { cin>>n>>m; f[1][1]=1;f[2][1]=-1; f[3][0]=1;f[4][0]=-1; f[5][0]=1;f[5][1]=-1; f[6][0]=-1;f[6][1]=1; f[7][0]=f[7][1]=1; f[8][0]=f[8][1]=-1; for(int i=1;i<=n;++i) cin>>s[i]+1; cin>>nme+1;len=strlen(nme+1); for(int i=1;i<=n&&!ok;++i) for(int j=1;j<=m&&!ok;++j) dfs((st[0]=i),(st[1]=j),1); if(!ok) cout<<"No Answer!"; return 0; }
JudgeOnline1428: 倒酒
题目描述
分别输入三个杯子容量a,b,c 且第一个为初始杯中的酒量,另外两个为空的。现要求你要精确量出
的e容量的酒。问最少通过几步能精确量出你所要的容量。.例如有三个烧杯容量分别为:80、50、30毫升,现在第一个杯中装满了80
毫升水,其余两个是空的。现要精确的40毫升水,不许用其它工具,请找出最少步骤的方法。 若超过50步,则认为这种计量方法太麻烦
,直接输出“no answer”
输入
80 50 30 40
输出
step1:30 50 0
step2:30 20 30
step3:60 20 0
step4:60 0 20
step5:10
50 20
step6:10 40 30
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=3e4+10; int a,b,c,e; int s=1,t=0,f[maxn][5],from[maxn],ans[110]; bool ok=0; bool ud(int x,int y,int z) { for(int i=1;i<=t;++i) if(f[i][1]==x&&f[i][2]==y&&f[i][3]==z&&f[i][0]<=f[s][0]+1) return 1; return 0; } void p() { if(f[t][1]!=e&&f[t][2]!=e&&f[t][3]!=e) return; ok=1; for(int i=t;i;i=from[i]) ans[f[i][0]]=i; for(int i=1;i<=f[t][0];++i) printf("step%d:%d %d %d\n",i,f[ans[i]][1],f[ans[i]][2],f[ans[i]][3]); } void bfs() { f[++t][0]=0;f[t][1]=a;f[t][2]=f[t][3]=0;p(); int x; while(s<=t&&!ok) { if(f[s][0]>=50) break; //1->2: x=min(f[s][1],b-f[s][2]); if(!ok&&x&&!ud(f[s][1]-x,f[s][2]+x,f[s][3])) { from[++t]=s; f[t][0]=f[s][0]+1; f[t][1]=f[s][1]-x;f[t][2]=f[s][2]+x;f[t][3]=f[s][3]; p(); } //1->3: x=min(f[s][1],c-f[s][3]); if(!ok&&x&&!ud(f[s][1]-x,f[s][2],f[s][3]+x)) { from[++t]=s; f[t][0]=f[s][0]+1; f[t][1]=f[s][1]-x;f[t][2]=f[s][2];f[t][3]=f[s][3]+x; p(); } //2->1: x=min(f[s][2],a-f[s][1]); if(!ok&&x&&!ud(f[s][1]+x,f[s][2]-x,f[s][3])) { from[++t]=s; f[t][0]=f[s][0]+1; f[t][1]=f[s][1]+x;f[t][2]=f[s][2]-x;f[t][3]=f[s][3]; p(); } //2->3: x=min(f[s][2],c-f[s][3]); if(!ok&&x&&!ud(f[s][1],f[s][2]-x,f[s][3]+x)) { from[++t]=s; f[t][0]=f[s][0]+1; f[t][1]=f[s][1];f[t][2]=f[s][2]-x;f[t][3]=f[s][3]+x; p(); } //3->1: x=min(f[s][3],a-f[s][1]); if(!ok&&x&&!ud(f[s][1]+x,f[s][2],f[s][3]-x)) { from[++t]=s; f[t][0]=f[s][0]+1; f[t][1]=f[s][1]+x;f[t][2]=f[s][2];f[t][3]=f[s][3]-x; p(); } //3->2: x=min(f[s][3],b-f[s][2]); if(!ok&&x&&!ud(f[s][1],f[s][2]+x,f[s][3]-x)) { from[++t]=s; f[t][0]=f[s][0]+1; f[t][1]=f[s][1];f[t][2]=f[s][2]+x;f[t][3]=f[s][3]-x; p(); } s++; } } int main() { cin>>a>>b>>c>>e; if(a<e) printf("no answer"); else { bfs(); if(!ok) printf("no answer"); } return 0; }
codevs1961 躲避大龙
你早上起来,慢悠悠地来到学校门口,发现已经是八点整了!(这句话里有一个比较重要的条件)
学校共有N个地点,编号为1~N,其中1号为学校门口(也就是你现在所处的位置),2号为你的教室(也就是你的目的地)。这些地点之间有M条双向道路,对于第i条道路,为了不引起值周队老师的怀疑,你通过它的时间须恰好为Ti秒。这个数可能为负数,意义为时间倒流。
不过,即使没有引起怀疑,值周队也布下了最后一道防线:大龙会在教室处不定期出现。当然,你也了解大龙的习性:当前时间的秒数越小,大龙出现的概率就越低,例如:8:13:06这一时刻的秒数是06,就要比8:12:57这个时刻更加安全。
现在的问题是,在不引起怀疑的前提下,最安全的到达时刻的秒数是多少。如果学校门口到教室没有路(-_-||),请输出60。
注意,你可以选择在途中的任何时候经过教室,而不结束“旅程”,具体见样例。
第一行为两个整数,N和M,意义在上面已经说过了。
第2行~第M+1行,每行代表一条道路。第i+1行代表第i条道路,这一行有3个整数,Ai,Bi,Ti,表示Ai号地点与Bi号地点有一条双向道路,通过它的时间必须为Ti秒。
只有一行,为最安全的到达时刻的秒数。
Input1:
2 1
2 1 54
Input2:
3 3
1 2 26
1 3 17
2 3 -9
Input3:
3 1
1 3 110
Input4:
2 2
1 2 7
2 1 9
Input5:
2 2
1 2 3
1 1 1
Input6:
2 2
1 2 9
1 2 11
Output1:
06
Output2:
00
Output3:
60
Output4:
01
Output5:
00
Output6:
01
样例1的说明:一共只有两个地点(多么福利的数据啊),也只有一条道路,耗时为54秒。最优方案为,经过这个道路9次,耗时486秒,即8分06秒,于8:08:06到达教室。当然,最优方案不唯一。
样例2的说明:走1->3->1->2,用时17+17+26,于8:01:00到达;或走1->2->3->1->2,用时26-9+17+26,于8:01:00到达。
对于20%的数据,N≤2;对于40%的数据,N≤100;对于70%的数据,N≤1000;
对于100%的数据,2≤N≤7000,0≤M≤9000,1≤Ai,Bi≤N,|Ti|≤109。
有一组数据全是大负数。要注意了。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=7e3+10,maxm=9e3+10; int n,m; bool g[maxn][70]; int aa,ff;char cc; int read() { aa=0;cc=getchar();ff=1; while(cc<'0'||cc>'9') { if(cc=='-') ff=-1; cc=getchar(); } while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa*ff; } int fir[maxn],nxt[2*maxm],to[2*maxm],e=0,v[2*maxm]; void add(int x,int y,int z) { to[++e]=y;nxt[e]=fir[x];fir[x]=e;v[e]=z; to[++e]=x;nxt[e]=fir[y];fir[y]=e;v[e]=z; } void s(int pos,int t) { g[pos][t]=1; int y,z,tt; for(y=fir[pos];y;y=nxt[y]) { z=to[y];tt=(t+v[y]+786666660)%60; if(!g[z][tt]) s(z,tt); } } int main() { n=read();m=read(); int x,y,z; for(int i=1;i<=m;++i) { x=read();y=read();z=read(); add(x,y,z); } s(1,0); for(int i=0;i<60;++i) if(g[2][i]) { if(i<10) cout<<"0"; cout<<i; return 0; } cout<<"60"; return 0; }
codevs1026 逃跑的拉尔夫
年轻的拉尔夫开玩笑地从一个小镇上偷走了一辆车,但他没想到的是那辆车属于警察局,并且车上装有用于发射车子移动路线的装置。
那个装置太旧了,以至于只能发射关于那辆车的移动路线的方向信息。
编写程序,通过使用一张小镇的地图帮助警察局找到那辆车。程序必须能表示出该车最终所有可能的位置。
小镇的地图是矩形的,上面的符号用来标明哪儿可以行车哪儿不行。“.”表示小镇上那块地方是可以行车的,而符号“X”表示此处不能行车。拉尔夫所开小车的初始位置用字符的“*”表示,且汽车能从初始位置通过。
汽车能向四个方向移动:向北(向上),向南(向下),向西(向左),向东(向右)。
拉尔夫所开小车的行动路线是通过一组给定的方向来描述的。在每个给定的方向,拉尔夫驾驶小车通过小镇上一个或更多的可行车地点。
输入文件的第一行包含两个用空格隔开的自然数R和C,1≤R≤50,1≤C≤50,分别表示小镇地图中的行数和列数。
以下的R行中每行都包含一组C个符号(“.”或“X”或“*”)用来描述地图上相应的部位。
接下来的第R+2行包含一个自然数N,1≤N≤1000,表示一组方向的长度。
接下来的N行幅行包含下述单词中的任一个:NORTH(北)、SOUTH(南)、WEST(西)和EAST(东),表示汽车移动的方向,任何两个连续的方向都不相同。
输出文件应包含用R行表示的小镇的地图(象输入文件中一样),字符“*”应该仅用来表示汽车最终可能出现的位置。
4 5
.....
.X...
...*X
X.X..
3
NORTH
WEST
SOUTH
.....
*X*..
*.*.X
X.X..
感觉自己回到了一年前刷搜索基础题的状态,难度差不多,为什么现在没有当时刷的快?
如果今年没去年考的好就搞笑了。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=1000+10,maxr=50+5; int n,R,C,sr[3]; char s[maxr][maxr]; char tn[maxn][10]; bool g[maxr][maxr][maxn]; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } bool ng(int x,int y) { if(!x||!y||x>R||y>C) return 0; if(s[x][y]!='.'&&s[x][y]!='*') return 0; return 1; } void dfs(int x,int y,int pos) { if(g[x][y][pos]||!ng(x,y)) return; g[x][y][pos]=1; if(tn[pos][0]=='N'&&ng(x-1,y)) dfs(x-1,y,pos); else if(tn[pos][0]=='S'&&ng(x+1,y)) dfs(x+1,y,pos); else if(tn[pos][0]=='W'&&ng(x,y-1)) dfs(x,y-1,pos); else if(tn[pos][0]=='E'&&ng(x,y+1)) dfs(x,y+1,pos); if(pos==n) { s[x][y]='*'; return; } if(tn[pos+1][0]=='N'&&ng(x-1,y)) dfs(x-1,y,pos+1); else if(tn[pos+1][0]=='S'&&ng(x+1,y)) dfs(x+1,y,pos+1); else if(tn[pos+1][0]=='W'&&ng(x,y-1)) dfs(x,y-1,pos+1); else if(tn[pos+1][0]=='E'&&ng(x,y+1)) dfs(x,y+1,pos+1); } int main() { R=read();C=read(); for(int i=1;i<=R;++i) cin>>s[i]+1; for(int i=1;i<=R;++i) for(int j=1;j<=C;++j) if(s[i][j]=='*') { sr[0]=i;sr[1]=j; s[i][j]='.'; break; } n=read(); for(int i=1;i<=n;++i) cin>>tn[i]; if(tn[1][0]=='N'&&ng(sr[0]-1,sr[1])) sr[0]--; else if(tn[1][0]=='S'&&ng(sr[0]+1,sr[1])) sr[0]++; else if(tn[1][0]=='W'&&ng(sr[0],sr[1]-1)) sr[1]--; else if(tn[1][0]=='E'&&ng(sr[0],sr[1]+1)) sr[1]++; dfs(sr[0],sr[1],1); for(int i=1;i<=R;++i) { for(int j=1;j<=C;++j) cout<<s[i][j]; cout<<"\n"; } return 0; }
codevs2924 数独挑战
“芬兰数学家因卡拉,花费3个月时间设计出了世界上迄今难度最大的数独游戏,而且它只有一个答案。因卡拉说只有思考能力最快、头脑最聪明的人才能破解这个游戏。”这是英国《每日邮报》2012年6月30日的一篇报道。这个号称“世界最难数独”的“超级游戏”,却被扬州一位69岁的农民花三天时间解了出来。
看到这个新闻后,我激动不已,证明我们OI的实力的机会来了,我们虽然不是思考能力最快、头脑最聪明的人,但是我们可以保证在1s之内解题。
好了废话不多说了……
数独是一种填数字游戏,英文名叫Sudoku,起源于瑞士,上世纪70年代由美国一家数学逻辑游戏杂志首先发表,名为Number Place,后在日本流行,1984年将Sudoku命名为数独,即“独立的数字”的省略,解释为每个方格都填上一个个位数。2004年,曾任中国香港高等法院法官的高乐德(Wayne Gould)把这款游戏带到英国,成为英国流行的数学智力拼图游戏。
玩家需要根据9×9盘面上的已知数字,推理出所有剩余位置(数据表示为数字0)的数字,并满足每一行、每一列、每一个粗线宫内的数字均含1-9,不重复。
现在给你一个数独,请你解答出来。每个数独保证有解且只有一个。
9行9列。
每个数字用空格隔开。0代表要填的数
行末没有空格,末尾没有回车。
输出答案。
排成9行9列。
行末没有空格,结尾可以有回车。
2 0 0 0 1 0 8 9 0
0 0 7 0 0 0 0 0 0
0 0 0 9 0 0 0 0 7
0 6 0 0 0 1 3 0 0
0 9 0 7 3 4 0 8 0
0 0 3 6 0 0 0 5 0
6 0 0 0 0 2 0 0 0
0 0 0 0 0 0 1 0 0
0 5 9 0 8 0 0 0 3
2 4 5 3 1 7 8 9 6
9 1 7 2 6 8 5 3 4
3 8 6 9 4 5 2 1 7
4 6 2 8 5 1 3 7 9
5 9 1 7 3 4 6 8 2
8 7 3 6 2 9 4 5 1
6 3 8 1 7 2 9 4 5
7 2 4 5 9 3 1 6 8
1 5 9 4 8 6 7 2 3
保证有解,每个数独都由<a href="http://oubk.com/">http://oubk.com</a>数独网提供。
其中数据hard1.in为芬兰数学家提供。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=12; int ans[maxn][maxn]; bool h[maxn][maxn],le[maxn][maxn],ge[maxn][maxn],ok=0; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } int get_ge(int x,int y) { x=(x-1)/3+1;y=(y-1)/3+1; return (x-1)*3+y; } bool kz(int x,int y,int num) { if(!num) return 0; int gg=get_ge(x,y); if(h[x][num]) return 0; if(le[y][num]) return 0; if(ge[gg][num]) return 0; h[x][num]=le[y][num]=ge[gg][num]=1; return 1; } void p() { ok=1; for(int i=1;i<=9;++i) { printf("%d",ans[i][1]); for(int j=2;j<=9;++j) printf(" %d",ans[i][j]); printf("\n"); } } void s(int x,int y) { if(x>9) p(); if(ok) return; int xx,yy; xx=x;yy=y+1;xx+=yy/10;yy=(yy-1)%9+1; if(ans[x][y]) s(xx,yy); else { for(int i=1;i<=9&&!ok;++i) if(kz(x,y,i)){ ans[x][y]=i; s(xx,yy); h[x][i]=le[y][i]=ge[get_ge(x,y)][i]=0; } ans[x][y]=0; } } int main() { for(int i=1;i<=9;++i) for(int j=1;j<=9;++j) ans[i][j]=read(),kz(i,j,ans[i][j]); s(1,1); return 0; }
JudgeOnline1433: 操练士兵
题目描述
如图1,由8个方格构成的训练场,间隔为虚线的表示两方格相通,五个士兵编号分别为1……5,初始时,士兵被随机地排列在任意的5个格子中。士兵可以越过虚线进入相邻的没有被其他士兵占据的格子中,每移动一格算一步。编程:给定5个士兵的初始位置,计算出将士兵排列为目标状态时最少的步数。输入:5个士兵的初始位置与目标位置。
输出:最优步数,若无解输出-1。样例读入:4567841638对应的输出为:2
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=1e6+10; int S,T,f[12][12]={{0},{2,5,2},{3,1,3,6},{2,2,7},{1,5},{3,1,4,6},{3,2,5,7},{3,3,6,8},{1,7}},ans[maxn],mi[maxn]; bool g[maxn],ok; bool kz(int x) { for(int i=1;i<5;++i) for(int j=i+1;j<=5;++j) if(x/mi[i-1]%10==x/mi[j-1]%10) return 0; return 1; } int zz[maxn]; void bfs() { int s=1,t=0,x,y,z; memset(ans,0x3f3f3f3f,sizeof(ans)); if(!kz(S)) return; zz[++t]=S;ans[S]=0;g[S]=1; while(s<=t&&!ok) { x=zz[s++]; for(int i=1;i<=5&&!ok;++i) { y=x/mi[i-1]%10; for(int j=1;j<=f[y][0]&&!ok;++j) { z=x+(f[y][j]-y)*mi[i-1]; if(!kz(z)||g[z]) continue; g[z]=1;zz[++t]=z; ans[z]=ans[x]+1; if(z==T) ok=1; } } } } int main() { cin>>S>>T; mi[0]=1; for(int i=1;i<=6;++i) mi[i]=mi[i-1]*10; bfs(); if(ans[T]!=0x3f3f3f3f) cout<<ans[T]; else cout<<"-1"; return 0; }
codevs1229 数字游戏
- 第一行包含两个整数 N和M(0<N<9,0<M<2000),分别代表纸片的数目和询问的数目。
- 第二行包含N个整数分别代表纸片上写的数字,每个数字可能取0~9。
- 接下来有M行询问,每个询问给出两个整数X和K(0<=x<10^9,0<K<100)。
- 对于每次询问,如果能够用这些纸片拼出符合答案的T,就输出结果T。如果有多个结果,就输出符合要求的最小的T。
- 如果不能拼出,就输出"None"。
4 3
1 2 3 4
5 7
33 6
12 8
1234
None
1324
本来说要搞一道中级水题来打来着,看到黄学长标签里面有一个哈希,就开了这题。
哪里有哈希了嘛。。。明明就是个裸的。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=12,maxtot=4e6; long long n,m,a[maxn],num[maxtot],tot=0; bool ok[maxn]; long long aa;char cc; long long read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } void s(int pos,long long x) { if(pos>n) { num[++tot]=x; return; } for(int i=1;i<=n;++i) if(!ok[i]){ ok[i]=1;s(pos+1,x*10+a[i]);ok[i]=0; } } void get_ans(long long x,long long y) { for(int i=1;i<=tot;++i) if((num[i]+x)%y==0) { printf("%lld\n",num[i]);return; } printf("None\n"); } int main() { n=read();m=read(); for(int i=1;i<=n;++i) a[i]=read(); s(1,(long long)0); sort(num+1,num+tot+1); tot=unique(num+1,num+tot+1)-(num+1); long long x,y; for(int i=1;i<=m;++i) { x=read();y=read(); get_ans(x,y); } return 0; }
bzoj1611 流星雨
Description
去年偶们湖南遭受N年不遇到冰冻灾害,现在芙蓉哥哥则听说另一个骇人听闻的消息: 一场流星雨即将袭击整个霸中,由于流星体积过大,它们无法在撞击到地面前燃烧殆尽, 届时将会对它撞到的一切东西造成毁灭性的打击。很自然地,芙蓉哥哥开始担心自己的 安全问题。以霸中至In型男名誉起誓,他一定要在被流星砸到前,到达一个安全的地方 (也就是说,一块不会被任何流星砸到的土地)。如果将霸中放入一个直角坐标系中, 芙蓉哥哥现在的位置是原点,并且,芙蓉哥哥不能踏上一块被流星砸过的土地。根据预 报,一共有M颗流星(1 <= M <= 50,000)会坠落在霸中上,其中第i颗流星会在时刻 T_i (0 <= T_i <= 1,000)砸在坐标为(X_i, Y_i) (0 <= X_i <= 300;0 <= Y_i <= 300) 的格子里。流星的力量会将它所在的格子,以及周围4个相邻的格子都化为焦土,当然 芙蓉哥哥也无法再在这些格子上行走。芙蓉哥哥在时刻0开始行动,它只能在第一象限中, 平行于坐标轴行动,每1个时刻中,她能移动到相邻的(一般是4个)格子中的任意一个, 当然目标格子要没有被烧焦才行。如果一个格子在时刻t被流星撞击或烧焦,那么芙蓉哥哥 只能在t之前的时刻在这个格子里出现。请你计算一下,芙蓉哥哥最少需要多少时间才能到 达一个安全的格子。
Input
* 第1行: 1个正整数:M * 第2..M+1行: 第i+1行为3个用空格隔开的整数:X_i,Y_i,以及T_i
Output
输出1个整数,即芙蓉哥哥逃生所花的最少时间。如果芙蓉哥哥无论如何都无法在流星雨中存活下来,输出-1
Sample Input
0 0 2
2 1 2
1 1 2
0 3 5
输入说明:
一共有4颗流星将坠落在霸中,它们落地点的坐标分别是(0, 0),(2, 1),(1, 1)
以及(0, 3),时刻分别为2,2,2,5。
Sample Output
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=300+10,INF=0x3f3f3f3f; int n,T[maxn][maxn],rf[5][3]={{0},{1,0},{-1,0},{0,1},{0,-1}},ans=INF; long long aa;char cc; long long read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } int dis[maxn][maxn],zz[maxn*maxn];//< void bfs() { int s=1,t=0,x,y,xx,yy; zz[++t]=0;dis[0][0]=0; while(s<=t&&ans==INF) { x=zz[s]/10000;y=zz[s]%10000;s++; for(int i=1;i<=4&&ans==INF;++i) { xx=x+rf[i][0];yy=y+rf[i][1]; if(xx<0||yy<0||dis[xx][yy]||!(xx+yy)) continue; if(dis[x][y]+1<T[xx][yy]) { dis[xx][yy]=dis[x][y]+1; if(T[xx][yy]==INF) ans=dis[xx][yy]; zz[++t]=xx*10000+yy; } else dis[xx][yy]=INF; } } } int main() { n=read();memset(T,0x3f3f3f3f,sizeof(T)); int x,y,z,xx,yy; for(int i=1;i<=n;++i) { x=read();y=read();z=read(); T[x][y]=min(T[x][y],z); for(int j=1;j<=4;++j) { xx=x+rf[j][0];yy=y+rf[j][1]; if(xx<0||yy<0) continue; T[xx][yy]=min(T[xx][yy],z); } } bfs(); if(ans!=INF)cout<<ans; else cout<<"-1"; return 0; }