搜索题集

 

HDU - 1241 Oil Deposits(求连通块的个数)

 

The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.

Input

The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either `*', representing the absence of oil, or `@', representing an oil pocket.

Output

For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.

Sample Input

1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5 
****@
*@@*@
*@**@
@@@*@
@@**@
0 0 

Sample Output

0
1
2
2
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int n,m;
int mov[8][2]={{1,0},{0,1},{-1,0},{0,-1},{1,1},{ 1,-1},{-1,1},{-1,- 1}};
char a[105][105];
void dfs(int x,int y){
	a[x][y]='*';//凡是进来的都是‘@’,尽管消除就行——还不用作标记llgl
	for(int i=0;i<8;i++){
		int xx=x+mov[i][0];
		int yy=y+mov[i][1];
		if(xx<0||xx>n||yy<0||yy>m) continue;
		if(a[xx][yy]!='@') continue;
		dfs(xx,yy);
	}
}
int main(){
	int r,c,sum;
	while(~scanf("%d%d",&n,&m)&&n){
		sum=0;
		for(int i=0;i<n;i++)//读二维字符技巧 
			cin>>a[i];
		for(int i=0;i<n;i++){ //挨个遍历 
			for(int j=0;j<m;j++){
				if(a[i][j]=='@'){
					dfs(i,j);
					sum++;
				}
			}
		}
		cout<<sum<<endl;
	}
	return 0;
}

 

 

 

HDU - 1584  蜘蛛牌(“特殊的”搜索)

 

蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起移动,游戏的目的是将所有的牌按同一花色从小到大排好,为了简单起见,我们的游戏只有同一花色的10张牌,从A到10,且随机的在一行上展开,编号从1到10,把第i号上的牌移到第j号牌上,移动距离为abs(i-j),现在你要做的是求出完成游戏的最小移动距离。

Input

第一个输入数据是T,表示数据的组数。
每组数据有一行,10个输入数据,数据的范围是[1,10],分别表示A到10,我们保证每组数据都是合法的。

Output

对应每组数据输出最小移动距离。

Sample Input

1
1 2 3 4 5 6 7 8 9 10

Sample Output

9
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath> 
using namespace std;
const int N=11;
int ans;
int a[N];
bool vis[N];
void dfs(int cnt,int sum){
	if(sum>ans)
		return;
	if(cnt==9){//当前是第10个数——over
		ans=sum;
		return;
	}
	for(int i=1;i<=10;i++){
		if(!vis[i]){//若该数未移位
			vis[i]=true;
			for(int j=i+1;j<=10;j++){ //移到哪家门下
				if(!vis[j]){
					//vis[j]=true;//他的“爸爸”是不需要被标记的,因为他还没移
					dfs(cnt+1,sum+abs(a[i]-a[j]));
					break; //此题特殊之处 
					//vis[j]=false;
				}
			}
			vis[i]=false;
		}
	}
}
int main(){
	int n,x,cnt,sum;
	cin>>n;
	while(n--){
		ans=0x3f3f3f;
		cnt=0;
		sum=0; 
		for(int i=1;i<=10;i++){
			cin>>x;
			a[x]=i; //牌面为x的牌放在i位置上 
		}
		memset(vis,false,sizeof vis);
		dfs(0,0);
		cout<<ans<<endl;
	}
	return 0;
}

 

 

 

 

HDU - 1716  排列2(全排列更简单)

 

Ray又对数字的列产生了兴趣:
现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数。

Input

每组数据占一行,代表四张卡片上的数字(0<=数字<=9),如果四张卡片都是0,则输入结束。

Output

对每组卡片按从小到大的顺序输出所有能由这四张卡片组成的4位数,千位数字相同的在同一行,同一行中每个四位数间用空格分隔。
每组输出数据间空一行,最后一组数据后面没有空行。

Sample Input

1 2 3 4
1 1 2 3
0 1 2 3
0 0 0 0

Sample Output

1234 1243 1324 1342 1423 1432
2134 2143 2314 2341 2413 2431
3124 3142 3214 3241 3412 3421
4123 4132 4213 4231 4312 4321

1123 1132 1213 1231 1312 1321
2113 2131 2311
3112 3121 3211

1023 1032 1203 1230 1302 1320
2013 2031 2103 2130 2301 2310
3012 3021 3102 3120 3201 3210
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int a[5];
int main(){
	int tag=0;
	while(scanf("%d%d%d%d",&a[0],&a[1],&a[2],&a[3])&&(a[0||a[1]]||a[2]||a[3])){
		if(tag) //若是新一组数据则tag=1
			cout<<endl;
		tag=1;
		int flag=1,tmp=-1;
		do{
			if(a[0]==0) //首位不可为零
				continue;
			if(flag) {  //该组第一个数时flag=1
				cout<<a[0]<<a[1]<<a[2]<<a[3];
				flag=0;
			}
			else if(tmp==a[0]) //否则如果与首位相同则同行
				cout<<" "<<a[0]<<a[1]<<a[2]<<a[3];
			else //否则回车
				cout<<endl<<a[0]<<a[1]<<a[2]<<a[3];
			tmp=a[0];//更新首位
		}while(next_permutation(a,a+4));
		cout<<endl;
	}
	return 0;
}

 

 

 

 

HDU - 1016 Prime Ring Problem(经典)

 

A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.

Note: the number of first circle should always be 1.

Input

n (0 < n < 20).

Output

The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.

You are to write a program that completes above process.

Print a blank line after each case.

Sample Input

6
8

Sample Output

Case 1:
1 4 3 2 5 6
1 6 5 2 3 4

Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,num,cnt;
int a[25];
bool vis[25];
int prime[25]={0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0};
void dfs(int x){//刚刚放好的数
	if(cnt==n-1&&prime[a[cnt]+1]){//除1已经放在第一个位置外剩下n-1个数,到第n-1个数直接“首尾判断”即可
		for(int i=0;i<n;i++){
			if(i) cout<<" ";
			cout<<a[i];
		}
		cout<<endl;
	}
	for(int i=2;i<=n;i++){
		if(!vis[i]&&prime[i+x]){//若当前i与刚放好的数之和为素数……
			vis[i]=1;
			a[++cnt]=i;
			dfs(i);
			vis[i]=0;
			cnt--;
		}
	}
}
int main(){
	while(scanf("%d",&n)!=EOF){
		num++;
		memset(vis,0,sizeof vis);
		memset(a,0,sizeof a);
		a[0]=1;
		cnt=0;
		printf("Case %d:\n",num);
		dfs(1);
		cout<<endl;
	}
	return 0;
}

 

 

 

 

HDU - 1312  Red and Black(广搜)

 

There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he can move only on black tiles.

Write a program to count the number of black tiles which he can reach by repeating the moves described above.

Input

The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.

There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.

'.' - a black tile
'#' - a red tile
'@' - a man on a black tile(appears exactly once in a data set)

Output

For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).

Sample Input

6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
...@...
###.###
..#.#..
..#.#..
0 0

Sample Output

45
59
6
13

 题意:红的不能走,问有多少块他能走到(加上初始位置)

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int n,m,sum;
char a[21][21];
bool vis[21][21];
int mov[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node{
	int x,y;
}p;
queue<node> q;
struct node p2;
void bfs(node p){
	vis[p.x][p.y]=1;
	q.push(p);
	while(!q.empty()){
		p=q.front(); //以它为基准 
		q.pop();
		for(int i=0;i<4;i++){
			int xx=p.x+mov[i][0];
			int yy=p.y+mov[i][1];
			if(xx<0||xx>=n||yy<0||yy>=m) continue;
			if(a[xx][yy]!='.'||vis[xx][yy]) continue;
			sum++;
			p2.x=xx; //重新使用变量 
			p2.y=yy;
			q.push(p2);
			vis[p2.x][p2.y]=1;
//			printf("(%d,%d)\n",xx,yy);
		}
	} 
} 
int main(){
	int flag;
	while(~scanf("%d %d",&m,&n)&&m){
		getchar();//字符串读入要当心!
		memset(a,'0',sizeof a);
		memset(vis,0,sizeof vis);
		sum=0;
		flag=0;		
		for(int i=0;i<n;i++)
			scanf("%s",&a[i]);
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				if(a[i][j]=='@'){
					sum++;
					p.x=i;
					p.y=j;
					flag=1;
					break;
				}
			}
			if(flag) break;
		}
		bfs(p);
		cout<<sum<<endl;
	}
	return 0;
}

 

 

 

 

HDU - 2612 Find a way(两次广搜)

 

Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki.
Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city. So yifenfei made arrangements with Merceki to meet at a KFC. There are many KFC in Ningbo, they want to choose one that let the total time to it be most smallest.
Now give you a Ningbo map, Both yifenfei and Merceki can move up, down ,left, right to the adjacent road by cost 11 minutes.

Input

The input contains multiple test cases.
Each test case include, first two integers n, m. (2<=n,m<=200).
Next n lines, each line included m character.
‘Y’ express yifenfei initial position.
‘M’    express Merceki initial position.
‘#’ forbid road;
‘.’ Road.
‘@’ KCF

Output

For each test case output the minimum total time that both yifenfei and Merceki to arrival one of KFC.You may sure there is always have a KFC that can let them meet.

Sample Input

4 4
Y.#@
....
.#..
@..M
4 4
Y.#@
....
.#..
@#.M
5 5
Y..@.
.#...
.#...
@..M.
#...#

Sample Output

66
88
66

 

题意:Y、M同时出发到任一@时间之和最小为多少(只可走‘.’)

思路:Y走一遍把到该@的时间消耗保存在a[][]里,M走一遍把到该@的时间消耗保存在b[][]里,主函数找到@的位置,将minn与a[i][j]+b[i][j]比较,更新最小值

#include<iostream>
#include<cstring>
#include<queue> 
#include<cmath>
#include<cstdio>
#define inf 0x3f3f3f
using namespace std;
const int MAX=202;
int a[MAX][MAX];
int b[MAX][MAX];
bool vis[MAX][MAX];
char map[MAX][MAX];
struct node{
	int x,y;
	int step;
};
node p,p2;
int n,m,ans=0x3f3f3f;
queue<node> q;
void init(){
	ans=inf;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			a[i][j]=inf;
			b[i][j]=inf;
		}
	}
}
void bfs(int x,int y,bool flag){
	int mov[4][2]={{1,0},{-1,0},{0,-1},{0,1}};
	int xx,yy;
	memset(vis,0,sizeof vis);
	p.x=x;
	p.y=y;
	p.step=0;
	vis[p.x][p.y]=1;
	q.push(p);
	while(!q.empty()){
		p=q.front();
		q.pop();
		if(map[p.x][p.y]=='@'){//出口
			if(!flag) a[p.x][p.y]=p.step;
			else b[p.x][p.y]=p.step; 
		}
		for(int i=0;i<4;i++){
			xx=p.x+mov[i][0];
			yy=p.y+mov[i][1];
			if(xx<0||xx>=n||yy<0||yy>=m) continue;
			if(map[xx][yy]=='#'||vis[xx][yy]) continue;
			p2.x=xx;
			p2.y=yy;
			p2.step=p.step+1;
			q.push(p2);
			vis[p2.x][p2.y]=true;
		}
	}
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		init();//a[][],b[][]初始化为最大值
		for(int i=0;i<n;i++)
			scanf("%s",map[i]);
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				if(map[i][j]=='Y'){
					memset(vis,false,sizeof vis);
					bfs(i,j,false);
				}
				if(map[i][j]=='M'){
					memset(vis,false,sizeof vis);
					bfs(i,j,true);
				}
			}
		}
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				if(map[i][j]=='@')
					ans=min(ans,a[i][j]+b[i][j]);
		printf("%d\n",ans*11);
	}
	return 0;
}

 

 

 

POJ - 3984  迷宫问题 (广搜+输出路径)

 

定义一个二维数组:

int maze[5][5] = {

	0, 1, 0, 0, 0,

	0, 1, 0, 1, 0,

	0, 0, 0, 0, 0,

	0, 1, 1, 1, 0,

	0, 0, 0, 1, 0,

};


它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

Input

一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

Output

左上角到右下角的最短路径,格式如样例所示。

Sample Input

0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

Sample Output

(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
#include<iostream> 
#include<cstring>
#include<cstdio>
using namespace std;
struct node{
	int x,y,pre;
}p[30];
int mov[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int a[6][6];
bool vis[6][6];
int front=0,cnt=1;
void print(int n){
	if(p[n].pre!=-1){
		print(p[n].pre);
		printf("(%d, %d)\n",p[n].x,p[n].y);
	}
}
void bfs(int x,int y){
	p[front].pre=-1;
	p[front].x=x;
	p[front].y=y;
	while(front<cnt){
		for(int i=0;i<4;i++){
			int xx=p[front].x+mov[i][0];
			int yy=p[front].y+mov[i][1];
			if(xx<0||xx>5||yy<0||yy>5) continue;
			if(a[xx][yy]==1||vis[xx][yy]) continue;
			vis[xx][yy]=1;
			p[cnt].x=xx;
			p[cnt].y=yy;
			p[cnt++].pre=front;
			if(xx==4&&yy==4) print(front); 
		}
		front++;
	}
}
int main(){
	for(int i=0;i<5;i++){
		for(int j=0;j<5;j++)
			cin>>a[i][j];
	}
	cout<<"(0, 0)\n";		
	bfs(0,0);
	cout<<"(4, 4)\n";
	return 0;
}

 

 

 

51Nod - 1384 全排列(嗯……全排列)

 

给出一个字符串S(可能有重复的字符),按照字典序从小到大,输出S包括的字符组成的所有排列。例如:S = "1312",

输出为:

 

1123

1132

1213

1231

1312

1321

2113

2131

2311

3112

3121

3211

Input

输入一个字符串S(S的长度 <= 9,且只包括0 - 9的阿拉伯数字)

Output

输出S所包含的字符组成的所有排列

Sample Input

1312

Sample Output

1123
1132
1213
1231
1312
1321
2113
2131
2311
3112
3121
3211
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int main() {
	char a[10];
	scanf("%s",&a);
	int len=strlen(a);
	sort(a,a+len);//从小到大
	do {
		if(a[0]==0) continue;
		printf("%s\n",a);
	} while(next_permutation(a,a+len));

	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值