寒假第四周训练——DFS题目汇总

Oil Deposits
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions:20263 Accepted: 10621

Description

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 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

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

Source

题意:求连通的@总共有几块(上下左右左上右下右上左下都算一块),典型dfs题。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <conio.h>
using namespace std;
char map[105][105];
int dx[3]={-1,0,1};
int dy[3]={-1,0,1};
int m,n;
char ch;

int judge(int x,int y)
{
	if (0<=x&&x<m&&0<=y&&y<n) return 1;
	else return 0;
}

void dfs(int i,int j)
{
	if (map[i][j]=='@')
	{
		map[i][j]='*';
		for (int i1=0;i1<3;i1++)
			for (int j1=0;j1<3;j1++)
				if(dx[i1]||dy[j1]&&judge(i+dx[i1],j+dy[j1])) dfs(i+dx[i1],j+dy[j1]);
	}
}

int main()
{
	while (scanf("%d%d",&m,&n)!=EOF)
	{
		scanf("%c",&ch);
		if (ch==' ') getchar();
		if (n==0 && m==0) break;
		int cnt=0;
		for (int i=0;i<m;i++)
		{
			for (int j=0;j<n;j++)
				scanf("%c",&map[i][j]);
			getchar();
		}
		for (int i=0;i<m;i++)
			for (int j=0;j<n;j++)
				if (map[i][j]=='@') {cnt++; dfs(i,j);}
		cout << cnt << endl;
	}
	return 0;
}
Sum It Up
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions:8564 Accepted: 4381

Description

Given a specified total t and a list of n integers, find all distinct sums using numbers from the list that add up to t. For example, if t = 4, n = 6, and the list is [4, 3, 2, 2, 1, 1], then there are four different sums that equal 4: 4, 3+1, 2+2, and 2+1+1. (A number can be used within a sum as many times as it appears in the list, and a single number counts as a sum.) Your job is to solve this problem in general.

Input

The input will contain one or more test cases, one per line. Each test case contains t, the total, followed by n, the number of integers in the list, followed by n integers x 1 , . . . , x n . If n = 0 it signals the end of the input; otherwise, t will be a positive integer less than 1000, n will be an integer between 1 and 12 (inclusive), and x 1 , . . . , x n will be positive integers less than 100. All numbers will be separated by exactly one space. The numbers in each list appear in nonincreasing order, and there may be repetitions.

Output

For each test case, first output a line containing `Sums of', the total, and a colon. Then output each sum, one per line; if there are no sums, output the line `NONE'. The numbers within each sum must appear in nonincreasing order. A number may be repeated in the sum as many times as it was repeated in the original list. The sums themselves must be sorted in decreasing order based on the numbers appearing in the sum. In other words, the sums must be sorted by their first number; sums with the same first number must be sorted by their second number; sums with the same first two numbers must be sorted by their third number; and so on. Within each test case, all sums must be distinct; the same sum cannot appear twice.

Sample Input

4 6 4 3 2 2 1 1
5 3 2 1 1
400 12 50 50 50 50 50 50 25 25 25 25 25 25
0 0

Sample Output

Sums of 4:
4
3+1
2+2
2+1+1
Sums of 5:
NONE
Sums of 400:
50+50+50+50+50+50+25+25+25+25
50+50+50+50+50+25+25+25+25+25+25

Source

题意:给你一个t然后从n个数中找到一个子串和为t。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int a[1005],b[1005];
int n,t,cnt;

int cmp(int a,int b)
{
	return a>b;
}

void dfs(int s,int p,int l)
{
	if (s>t)
		return;
	else if(s==t)
	{
        printf("%d",b[0]);
        for(int i=1;i<l;i++)
            printf("+%d",b[i]);
        printf("\n");
        cnt++;		
	}
	else
	{
        for(int i=p;i<n;i++)
        {
            b[l]=a[i];
            dfs(s+a[i],i+1,l+1);
            while (i+1<n&&a[i]==a[i+1])
                i++;	
		}	
	} 
}

int main()
{
	while(cin >> t >> n && n && t)
	{
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		for (int i=0;i<n;i++)
			scanf("%d",&a[i]);
		sort(a,a+n,cmp);
		printf("Sums of %d:\n",t);
		cnt=0;
		dfs(0,0,0);
		if (!cnt)	printf("NONE\n");
	}
}

N皇后问题

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 29001    Accepted Submission(s): 12749


Problem Description
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。

 

Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
 

Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
 

Sample Input
 
 
1 8 5 0
 

Sample Output
 
 
1 92 10
 

Author
cgf
 

Source

题意:n皇后问题,直接用的以前写的代码。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int sum=0,n;
int a[15][15],b[15];


int ju(int i,int j)
{
	if (1<=i&&i<=n&&1<=j&&j<=n) return 1;
	else return 0;
}

int judge(int i,int j)
{
	int k,flag=1;
	for (k=1;k<=n;k++)
	{
		if (ju(i-k,j)&&a[i-k][j]==1) {flag=0;break;}
		else if (ju(i-k,j-k)&&a[i-k][j-k]==1) {flag=0;break;}
		else if (ju(i-k,j+k)&&a[i-k][j+k]==1) {flag=0;break;}
	}
	return flag;
}

void dfs(int i,int j)
{
	while (j<=n)
	{
		if (judge(i,j))
		{
			a[i][j]=1;
			if (i==n) sum++;
			else dfs(i+1,1);
			a[i][j]=0;
		}
	    j++;
	}
}

int main()
{
	for (int i=1;i<=10;i++)
	{
		n=i; sum=0;
		memset(a,0,sizeof(a));
		dfs(1,1);
		b[i]=sum;
		//printf("%d\n",b[i]);
	}
	while(cin >> n && n)
	{
		printf("%d\n",b[n]);
	}
	return 0;
}
Sudoku
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions:22005 Accepted:10431 Special Judge

Description

Sudoku is a very simple task. A square table with 9 rows and 9 columns is divided to 9 smaller squares 3x3 as shown on the Figure. In some of the cells are written decimal digits from 1 to 9. The other cells are empty. The goal is to fill the empty cells with decimal digits from 1 to 9, one digit per cell, in such way that in each row, in each column and in each marked 3x3 subsquare, all the digits from 1 to 9 to appear. Write a program to solve a given Sudoku-task. 

Input

The input data will start with the number of the test cases. For each test case, 9 lines follow, corresponding to the rows of the table. On each line a string of exactly 9 decimal digits is given, corresponding to the cells in this line. If a cell is empty it is represented by 0.

Output

For each test case your program should print the solution in the same format as the input data. The empty cells have to be filled according to the rules. If solutions is not unique, then the program may print any one of them.

Sample Input

1
103000509
002109400
000704000
300502006
060000050
700803004
000401000
009205800
804000107

Sample Output

143628579
572139468
986754231
391542786
468917352
725863914
237481695
619275843
854396127

Source

题意:填完数独,这题很容易超时,状态需要存的合理。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int map[10][10],r[10][10],c[10][10],t[3][3][10];
int flag;
char ch;

void judge(int n)
{
	int x=n/9,y=n%9;
	if (flag) return;
    if (n==81) 
    {  
        for(int i=0;i<9;i++)  
        {  
            for(int j=0;j<9;j++)  
            {  
                printf("%d",map[i][j]);   
            }  
            printf("\n");  
        }  
        flag=1;
        return;  
    }
    
	if (map[x][y]==0) 
	{
		for(int i=1;i<=9;i++)
		{
			if (!(r[x][i]||c[y][i]||t[x/3][y/3][i]))
			{
				map[x][y]=i;
				t[x/3][y/3][i]=r[x][i]=c[y][i]=1;
				judge(n+1);
				t[x/3][y/3][i]=r[x][i]=c[y][i]=0;	
				map[x][y]=0;							
			}
		}
	}
	else judge(n+1);
}

int main()
{
	int n; cin >> n; getchar();
	while(n--)
	{
		flag=0;
		memset(map,0,sizeof(map));
		memset(c,0,sizeof(c));
		memset(r,0,sizeof(r));
		memset(t,0,sizeof(t));
		for (int i=0;i<9;i++)
		{
			for (int j=0;j<9;j++)
			{
				scanf("%c",&ch);
				map[i][j]=ch-'0';	
				if (map[i][j])
				{
					c[j][map[i][j]]=1;
					r[i][map[i][j]]=1;
					t[i/3][j/3][map[i][j]]=1;						
				}
			} 		
			getchar();	
		}
		judge(0);
	}
	return 0;
}
A Knight's Journey
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions:48884 Accepted: 16589

Description

Background 
The knight is getting bored of seeing the same black and white squares again and again and has decided to make a journey 
around the world. Whenever a knight moves, it is two squares in one direction and one square perpendicular to this. The world of a knight is the chessboard he is living on. Our knight lives on a chessboard that has a smaller area than a regular 8 * 8 board, but it is still rectangular. Can you help this adventurous knight to make travel plans? 

Problem 
Find a path such that the knight visits every square once. The knight can start and end on any square of the board.

Input

The input begins with a positive integer n in the first line. The following lines contain n test cases. Each test case consists of a single line with two positive integers p and q, such that 1 <= p * q <= 26. This represents a p * q chessboard, where p describes how many different square numbers 1, . . . , p exist, q describes how many different square letters exist. These are the first q letters of the Latin alphabet: A, . . .

Output

The output for every scenario begins with a line containing "Scenario #i:", where i is the number of the scenario starting at 1. Then print a single line containing the lexicographically first path that visits all squares of the chessboard with knight moves followed by an empty line. The path should be given on a single line by concatenating the names of the visited squares. Each square name consists of a capital letter followed by a number. 
If no such path exist, you should output impossible on a single line.

Sample Input

3
1 1
2 3
4 3

Sample Output

Scenario #1:
A1

Scenario #2:
impossible

Scenario #3:
A1B3C1A2B4C2A3B1C3A4B2C4

Source

题意:跳马问题,从A按一定顺序跳到B,可能的话输出路径,否则输出impossible。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int map[30][30],path[30][30],cnt=0,flag,p,q;
int dx[8]={-1,1,-2,2,-2,2,-1,1};
int dy[8]={-2,-2,-1,-1,1,1,2,2};

int judge(int x,int y)  
{  
    if(x>=1&&x<=p&&y>=1&&y<=q&&!map[x][y]&&!flag) return 1;  
    else return 0;  
}

void dfs(int r,int c,int step)
{
	path[step][0]=r;
	path[step][1]=c;
	if (step==p*q)
	{
		flag=1;
		return;
	}
    for(int i=0;i<8;i++)
    {
        int nx=r+dx[i];
        int ny=c+dy[i];
        if(judge(nx,ny))
        {
            map[nx][ny]=1;
            dfs(nx,ny,step+1);
            map[nx][ny]=0;
        }
    }
}

int main()
{
	int n; cin >> n;
	while(n--)
	{
		flag=0;
		memset(map,0,sizeof(map));
		memset(path,0,sizeof(path));
		scanf("%d%d",&p,&q);
		map[1][1]=1;
		dfs(1,1,1);
		printf("Scenario #%d:\n",++cnt);
        if(flag)  
        {  
            for(int i=1;i<=p*q;i++)  
                printf("%c%d",path[i][1]-1+'A',path[i][0]);  
        }
        else  
            printf("impossible");  
        printf("\n");
        if(n!=0)
            printf("\n");	
	}
	return 0;
} 

Prime Ring Problem

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 59738    Accepted Submission(s): 25849


Problem Description
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
 

Source

题意:n个数组成一个环使得相邻两个数之和为素数。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int p[50],a[25],vis[25],n,cnt=0;

void dfs(int pos)
{
	if (pos == n && p[a[0]+a[n-1]])
	{
		printf("%d",a[0]);
		for (int i=1;i<n;i++)
			printf(" %d",a[i]);
		printf("\n");
	}
	else for (int i=2;i<=n;i++)
	{
		if (!vis[i]&&p[i+a[pos-1]])
		{
			a[pos]=i;
			vis[i]=1;
			dfs(pos+1);
			vis[i]=0;
		}
	}
}

int main()
{
	memset(p,1,sizeof(p)); p[1]=0;
	for (int i=2;i<=40;i++)
	{
		if (p[i])
		{
			for (int j=2*i;j<=40;j+=i)
				p[j]=0;
		}
	}
	while(cin >> n)
	{
		a[0]=1;
		memset(vis,0,sizeof(vis));
		printf("Case %d:\n",++cnt);
		dfs(1);
		printf("\n");
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值