搜索复习-基础水题(一共12道)

由于是跟着黄学长刷题,此篇博文里所有JudgeOnline都是http://218.5.5.242:9018/JudgeOnline/

tyvj1080 N皇后

描述

检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。 

         列号
   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的帐号将被无警告删除 

输入格式

一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。 

输出格式

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。 

测试样例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 特殊的质数肋骨

题目描述 Description

农民约翰的母牛总是产生最好的肋骨。 你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们。 农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还剩下的肋骨上的数字都组成一个质数,举例来说: 7 3 3 1 全部肋骨上的数字 7331是质数;三根肋骨 733是质数;二根肋骨 73 是质数;当然,最后一根肋骨 7 也是质数。 7331 被叫做长度 4 的特殊质数。 写一个程序对给定的肋骨的数目 N(1<=N<=8),求出所有的特殊质数。 数字1不被看作一个质数。

输入描述 Input Description

单独的一行包含N。

输出描述 Output Description

按顺序输出长度为 N 的特殊质数,每行一个。

样例输入 Sample Input

4

样例输出 Sample Output
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

样例输出
1
 
感觉还是弄一点不是这么无脑的搜索来刷好一点
//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表示不相邻)

输出

最多的填色方案

样例输入

8
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

样例输出

15552
 
感觉自己已经堕落了。。。
//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的字符矩阵。接下来一行是一串字符,代表要寻找的国都名。

输出

如果没有找到,则输出“No Answer!”;
如果有找到,输出分两行,第一行为国都名的起始位置坐标,第二行为寻找的方向

样例输入

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

 
真的很好写。ctrl-c + ctrl-v
//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 躲避大龙

题目描述 Description

你早上起来,慢悠悠地来到学校门口,发现已经是八点整了!(这句话里有一个比较重要的条件)

学校共有N个地点,编号为1~N,其中1号为学校门口(也就是你现在所处的位置),2号为你的教室(也就是你的目的地)。这些地点之间有M条双向道路,对于第i条道路,为了不引起值周队老师的怀疑,你通过它的时间须恰好为Ti秒。这个数可能为负数,意义为时间倒流。

不过,即使没有引起怀疑,值周队也布下了最后一道防线:大龙会在教室处不定期出现。当然,你也了解大龙的习性:当前时间的秒数越小,大龙出现的概率就越低,例如:8:13:06这一时刻的秒数是06,就要比8:12:57这个时刻更加安全。

现在的问题是,在不引起怀疑的前提下,最安全的到达时刻的秒数是多少。如果学校门口到教室没有路(-_-||),请输出60。

注意,你可以选择在途中的任何时候经过教室,而不结束“旅程”,具体见样例。

输入描述 Input Description

第一行为两个整数,N和M,意义在上面已经说过了。

第2行~第M+1行,每行代表一条道路。第i+1行代表第i条道路,这一行有3个整数,Ai,Bi,Ti,表示Ai号地点与Bi号地点有一条双向道路,通过它的时间必须为Ti秒。

输出描述 Output Description

只有一行,为最安全的到达时刻的秒数。

样例输入 Sample Input

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

样例输出 Sample Output

Output1:

06

Output2:

00

Output3:

60

Output4:

01

Output5:

00

Output6:

01

数据范围及提示 Data Size & Hint

样例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 逃跑的拉尔夫

题目描述 Description

年轻的拉尔夫开玩笑地从一个小镇上偷走了一辆车,但他没想到的是那辆车属于警察局,并且车上装有用于发射车子移动路线的装置。

那个装置太旧了,以至于只能发射关于那辆车的移动路线的方向信息。

编写程序,通过使用一张小镇的地图帮助警察局找到那辆车。程序必须能表示出该车最终所有可能的位置。

小镇的地图是矩形的,上面的符号用来标明哪儿可以行车哪儿不行。“.”表示小镇上那块地方是可以行车的,而符号“X”表示此处不能行车。拉尔夫所开小车的初始位置用字符的“*”表示,且汽车能从初始位置通过。

汽车能向四个方向移动:向北(向上),向南(向下),向西(向左),向东(向右)。

拉尔夫所开小车的行动路线是通过一组给定的方向来描述的。在每个给定的方向,拉尔夫驾驶小车通过小镇上一个或更多的可行车地点。

输入描述 Input Description

输入文件的第一行包含两个用空格隔开的自然数R和C,1≤R≤50,1≤C≤50,分别表示小镇地图中的行数和列数。

以下的R行中每行都包含一组C个符号(“.”或“X”或“*”)用来描述地图上相应的部位。

接下来的第R+2行包含一个自然数N,1≤N≤1000,表示一组方向的长度。

接下来的N行幅行包含下述单词中的任一个:NORTH(北)、SOUTH(南)、WEST(西)和EAST(东),表示汽车移动的方向,任何两个连续的方向都不相同。

输出描述 Output Description

输出文件应包含用R行表示的小镇的地图(象输入文件中一样),字符“*”应该仅用来表示汽车最终可能出现的位置。

 

样例输入 Sample Input

4 5

.....

.X...

...*X

X.X..

3

NORTH

WEST

SOUTH

 

样例输出 Sample Output

.....

*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 数独挑战

题目描述 Description

“芬兰数学家因卡拉,花费3个月时间设计出了世界上迄今难度最大的数独游戏,而且它只有一个答案。因卡拉说只有思考能力最快、头脑最聪明的人才能破解这个游戏。”这是英国《每日邮报》2012年6月30日的一篇报道。这个号称“世界最难数独”的“超级游戏”,却被扬州一位69岁的农民花三天时间解了出来。

看到这个新闻后,我激动不已,证明我们OI的实力的机会来了,我们虽然不是思考能力最快、头脑最聪明的人,但是我们可以保证在1s之内解题。

好了废话不多说了……

数独是一种填数字游戏,英文名叫Sudoku,起源于瑞士,上世纪70年代由美国一家数学逻辑游戏杂志首先发表,名为Number Place,后在日本流行,1984年将Sudoku命名为数独,即“独立的数字”的省略,解释为每个方格都填上一个个位数。2004年,曾任中国香港高等法院法官的高乐德(Wayne Gould)把这款游戏带到英国,成为英国流行的数学智力拼图游戏。

  玩家需要根据9×9盘面上的已知数字,推理出所有剩余位置(数据表示为数字0)的数字,并满足每一行、每一列、每一个粗线宫内的数字均含1-9,不重复。

现在给你一个数独,请你解答出来。每个数独保证有解且只有一个。

输入描述 Input Description

9行9列。

每个数字用空格隔开。0代表要填的数

行末没有空格,末尾没有回车。

输出描述 Output Description

输出答案。

排成9行9列。

行末没有空格,结尾可以有回车。

样例输入 Sample Input

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

样例输出 Sample Output

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

数据范围及提示 Data Size & Hint

保证有解,每个数独都由<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。
样例读入:
45678
41638
对应的输出为:
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 数字游戏

题目描述 Description
Lele 最近上课的时候都很无聊,所以他发明了一个数字游戏来打发时间。  这个游戏是这样的,首先,他拿出几张纸片,分别写上0到9之间的任意数字(可重复写某个数字),然后,他叫同学随便写两个数字X和K。Lele要做的事情就是重新拼这些纸牌,组成数字 T ,并且 T + X 是 K 的正整数倍。 有时候,当纸片很多的时候,Lele经常不能在一节课之内拼出来,但是他又想知道答案,所以,他想请你帮忙写一个程序来计算答案。  
输入描述 Input Description
  1. 第一行包含两个整数 N和M(0<N<9,0<M<2000),分别代表纸片的数目和询问的数目。  
  2. 第二行包含N个整数分别代表纸片上写的数字,每个数字可能取0~9。  
  3. 接下来有M行询问,每个询问给出两个整数X和K(0<=x<10^9,0<K<100)。 
输出描述 Output Description
  1. 对于每次询问,如果能够用这些纸片拼出符合答案的T,就输出结果T。如果有多个结果,就输出符合要求的最小的T。  
  2. 如果不能拼出,就输出"None"。  
样例输入 Sample Input

4 3 

1 2 3 4 

5 7 

33 6 

12 8  

样例输出 Sample Output

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

4
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

5
 
走到x>300或y>300也可以。裸bfs。
//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;
}

  

posted @ 2017-09-19 20:10  shixinyi  阅读(441)  评论(0编辑  收藏  举报