DFS深搜习题

1.kkksc03考前临时抱佛脚

题目背景(洛谷P2392)

kkksc03 的大学生活非常的颓废,平时根本不学习。但是,临近期末考试,他必须要开始抱佛脚,以求不挂科。

题目描述

这次期末考试,kkksc03 需要考 4科。因此要开始刷习题集,每科都有一个习题集,分别有 s1​,s2​,s3​,s4​ 道题目,完成每道题目需要一些时间,可能不等(A1,A2,.....,As1​​,B1​,B2​,…,Bs2​​,C1​,C2​,…,Cs3​​,D1​,D2​,…,Ds4​​)。

kkksc03 有一个能力,他的左右两个大脑可以同时计算 22 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。

由于 kkksc03 还急着去处理洛谷的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。

输入格式

本题包含 5 行数据:第 1 行,为四个正整数 s1​,s2​,s3​,s4​。

第 22 行,为 A1​,A2​,…,As1​​ 共s1​ 个数,表示第一科习题集每道题目所消耗的时间。

第 33 行,为 B1​,B2​,…,Bs2​​ 共 s2​ 个数。

第 44 行,为 C1​,C2​,…,Cs3​​ 共 s3​ 个数。

第 55 行,为 D1​,D2​,…,Ds4​​ 共 s4​ 个数,意思均同上。

输出格式

输出一行,为复习完毕最短时间。

输入输出样例

输入 

1 2 1 3		
5
4 3
6
2 4 3

输出 

20

说明/提示

1≤ s1,s2,s3,s4≤ 20。

1≤

A1,A2,......,As1,B1,B2,......,Bs2,C1,C2,......,Cs3,D1,D2,.....,Ds4≤60。

#include<bits/stdc++.h>
using namespace std;
int a[5],s[20],f[1000],ans,sum;
int main() {
	for(int i=1; i<=4; i++)
		cin>>a[i];
	for(int k=1; k<=4; k++) {
		sum=0;
		for(int j=1; j<=a[k]; j++) {
			cin>>s[j];
			sum+=s[j];
		}
		memset(f,0,sizeof(f));
		f[0]=1;
		for(int i=1; i<=a[k]; i++)
			for(int j=sum; j>=0; j--)
				if(f[j])
					f[j+s[i]]=1;
		int n=sum,x;
		for(int i=0; i<=sum; i++)
			if(f[i] && n>=abs(i-(sum-i))) {
				n=abs(i-(sum-i));
				x=max(i,sum-i);
			}
		ans+=x;
	}
	cout<<ans;
}

2.[NOIP2002 普及组] 选数

题目描述(洛谷P1036)

已知 n个整数 x1,x2,....,xn​,以及 11 个整数 kk(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)。

第二行 n 个整数,分别为 x1,x2,⋯,xn​(1≤xi​≤5×10^6)。

输出格式

输出一个整数,表示种类数。

输入输出样例

输入 

4 3
3 7 12 19

输出 

1

说明/提示

【题目来源】

NOIP 2002 普及组第二题

#include<bits/stdc++.h>
using namespace std;
bool isprime(int a) {
	for(int i=2;i*i<=a;i++)
		if(a%i==0)
			return false;
	return true;
}
int a[25];
int n,k,ans;
void dfs(int m, int sum, int x) {
	if(m==k) {
		if(isprime(sum))
			ans++;
		return ;
	}
	for(int i=x;i<=n-1;i++)
		dfs(m+1,sum+a[i],i+1);
	return;
}
int main(){
	cin>>n>>k;
	for(int i = 0; i < n; i++)
		cin>>a[i];
	dfs(0,0,0);
	cout<<ans;
	return 0;
}

3.[COCI2008-2009 #2] PERKET

题目描述(洛谷P2036)

Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 nn 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 s 和苦度 b。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。

众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。

另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。

输入格式

第一行一个整数 n,表示可供选用的食材种类数。

接下来 n 行,每行 2 个整数si​ 和 bi​,表示第 i 种食材的酸度和苦度。

输出格式

一行一个整数,表示可能的总酸度和总苦度的最小绝对差。

输入输出样例

输入 #1

1
3 10

输出 #1

7

输入 #2

2
3 8
5 8

输出 #2

1

输入 #3

4
1 7
2 6
3 8
4 9

输出 #3

1

说明/提示

数据规模与约定

对于 100% 的数据,有 1≤n≤10,且将所有可用食材全部使用产生的总酸度和总苦度小于 

1×10^9,酸度和苦度不同时为 1 和 0。

#include<bits/stdc++.h>
using namespace std;
int s[20],b[20],f[20];
int n,j,c=1,y,ans=1e9;
void dfs(int x) {
	if(x<=n)
		for(int i=1; i<=n; i++)
			if(!f[i]) {
				c*=s[i];
				y+=b[i];
				ans=min(ans, abs(c - y));
				f[i]=1;
				dfs(x+1);
				f[i]=0;
				c/=s[i];
				y-=b[i];
			}
}
int main() {
	cin>>n;
	for(int i=1; i<=n; i++)
		cin>>s[i]>>b[i];
	dfs(1);
	cout<<ans<<endl;
	return 0;
}

4.迷宫

题目描述(洛谷P1605)

给定一个 N×M 方格的迷宫,迷宫里有 T 处障碍,障碍处不可通过。

在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。

输入格式

第一行为三个正整数 N,M,T,分别表示迷宫的长宽和障碍总数。

第二行为四个正整数 SX,SY,FX,FY,SX,SY 代表起点坐标,FX,FY 代表终点坐标。

接下来 T 行,每行两个正整数,表示障碍点的坐标。

输出格式

输出从起点坐标到终点坐标的方案总数。

输入输出样例

输入 

2 2 1
1 1 2 2
1 2

输出 

1

说明/提示

对于 100% 的数据,1≤N,M≤5,1≤T≤10,1≤SX,FX≤n,1≤SY,FY≤m。

#include<bits/stdc++.h>
using namespace std;
int n,m,t;
int s[10][10];
int vis[10][10];
int sx,sy;
int fx,fy;
int dx[]= {-1,1,0,0};
int dy[]= {0,0,-1,1};
int sum;
void dfs(int x,int y) {
	if(x==fx&&y==fy&&!s[x][y]) {
		sum++;
		return;
	} else {
		for(int i=0; i<4; i++) {
			int xx=x+dx[i];
			int yy=y+dy[i];
			if(x>=1&&y>=1&&x<=n&&y<=m&&!vis[x][y]&&!s[x][y]) {
				vis[x][y]=1;
				dfs(xx,yy);
				vis[x][y]=0;
			}
		}
	}
}
int main() {
	cin>>n>>m>>t;
	cin>>sx>>sy;
	cin>>fx>>fy;
	for(int i=1; i<=t; i++) {
		int x,y;
		cin>>x>>y;
		s[x][y]=1;
	}
	dfs(sx,sy);
	cout<<sum<<endl;

	return 0;
}

5.单词方阵

题目描述

给一 n×n 的字母方阵,内可能蕴含多个 yizhong 单词。单词在方阵中是沿着同一方向连续摆放的。摆放可沿着 8 个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间可以交叉,因此有可能共用字母。输出时,将不是单词的字母用 * 代替,以突出显示单词。

输入格式

第一行输入一个数 n。(7≤n≤100)。

第二行开始输入n×n 的字母矩阵。

输出格式

突出显示单词的 n×n 矩阵。

输入输出样例

输入 #1

7
aaaaaaa
aaaaaaa
aaaaaaa
aaaaaaa
aaaaaaa
aaaaaaa
aaaaaaa

输出 #1

*******
*******
*******
*******
*******
*******
*******

输入 #2

8
qyizhong
gydthkjy
nwidghji
orbzsfgz
hhgrhwth
zzzzzozo
iwdfrgng
yyyygggg

输出 #2

*yizhong
gy******
n*i*****
o**z****
h***h***
z****o**
i*****n*
y******g
#include <bits/stdc++.h>
using namespace std;
int n;
char a[101][101];
bool vis[101][101];
int mx[9]= {0, -1, -1, 0, 1, 1, 1, 0, -1};
int my[9]= {0, 0, 1, 1, 1, 0, -1, -1, -1};
int ans[8][3];
void dfs(int x, int y, char c, int dir) {
	if(c=='g') {
		for(int i=1; i<=7; ++i) {
			int row=ans[i][1];
			int col=ans[i][2];
			vis[row][col]=true;
		}
		return;
	}
	if(c=='y') {
		for(int i=1; i<=8; ++i) {
			int xx=x+mx[i];
			int yy=y+my[i];
			if(a[xx][yy]=='i') {
				ans[2][1]=xx;
				ans[2][2]=yy;
				dfs(xx, yy, 'i', i);
			}
		}
	} else if(c=='i') {
		int xx=x+mx[dir];
		int yy=y+my[dir];
		if(a[xx][yy]=='z') {
			ans[3][1]=xx;
			ans[3][2]=yy;
			dfs(xx, yy, 'z', dir);
		}
	} else if(c=='z') {
		int xx=x+mx[dir];
		int yy=y+my[dir];
		if(a[xx][yy]=='h') {
			ans[4][1]=xx;
			ans[4][2]=yy;
			dfs(xx, yy, 'h', dir);
		}
	} else if(c=='h') {
		int xx=x+mx[dir];
		int yy=y+my[dir];
		if(a[xx][yy]=='o') {
			ans[5][1]=xx;
			ans[5][2]=yy;
			dfs(xx, yy, 'o', dir);
		}
	} else if(c=='o') {
		int xx=x+mx[dir];
		int yy=y+my[dir];
		if(a[xx][yy]=='n') {
			ans[6][1]=xx;
			ans[6][2]=yy;
			dfs(xx, yy, 'n', dir);
		}
	} else if(c=='n') {
		int xx=x+mx[dir];
		int yy=y+my[dir];
		if(a[xx][yy]=='g') {
			ans[7][1]=xx;
			ans[7][2]=yy;
			dfs(xx, yy, 'g', dir);
		}
	}
}
int main() {
	scanf("%d", &n);
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=n; ++j) {
			cin >> a[i][j];
		}
	}
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=n; ++j) {
			if(a[i][j]=='y') {
				ans[1][1]=i;
				ans[1][2]=j;
				dfs(i, j, 'y', 0);
			}
		}
	}
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=n; ++j) {
			if(vis[i][j]==false) {
				a[i][j]='*';
			}
		}
	}
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=n; ++j) {
			printf("%c", a[i][j]);
		}
		printf("\n");
	}
	return 0;
}

 6.自然数的拆分问题 

题目描述(洛谷P2404)

任何一个大于 11 的自然数 nn,总可以拆分成若干个小于 nn 的自然数之和。现在给你一个自然数 nn,要求你求出 nn 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。

输入格式

输入:待拆分的自然数 nn。

输出格式

输出:若干数的加法式子。

输入输出样例

输入 

7

输出 

1+1+1+1+1+1+1
1+1+1+1+1+2
1+1+1+1+3
1+1+1+2+2
1+1+1+4
1+1+2+3
1+1+5
1+2+2+2
1+2+4
1+3+3
1+6
2+2+3
2+5
3+4

说明/提示

数据保证,2≤n≤8。

​
#include<bits/stdc++.h>
using namespace std;
int a[10001]= {1},n,total;
void print(int t) {
	for(int i=1; i<=t-1; i++)//输出一种方案解
		cout<<a[i]<<'+';
	cout<<a[t]<<endl;
	total++;//方案数加一
}
void search(int s,int t) {
	for(int i=a[t-1]; i<=s; i++)
		if(i<n) {  //当前数i要大于等于前1位数且不超过n
			a[t]=i;  //保存当前拆分数 i
			s-=i;  //s减去数i,s的值继续拆分
			if(s==0) print(t);  //当 s=0 时,拆分结束输出结果
			else search(s,t+1);  //当 s>0 时,继续递归
			s+=i;  //回溯:加上拆分的数,以便产生所有可能的拆分
		}
}
int main() {
	cin>>n;
	search(n,1);  //将要拆分的数n传递给s
	return 0;
}

​

7.[USACO10OCT] Lake Counting S

题目描述(l洛谷P1596)

Due to recent rains, water has pooled in various places in Farmer John's field, which is represented by a rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water ('W') or dry land ('.'). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors. Given a diagram of Farmer John's field, determine how many ponds he has.

输入格式

Line 1: Two space-separated integers: N and M * Lines 2..N+1: M characters per line representing one row of Farmer John's field. Each character is either 'W' or '.'. The characters do not have spaces between them.

输出格式

Line 1: The number of ponds in Farmer John's field.

题意翻译

由于近期的降雨,雨水汇集在农民约翰的田地不同的地方。我们用N×M(1≤N≤100,1≤M≤100) 的网格图表示。每个网格中有水(W) 或是旱地(.)。一个网格与其周围的八个网格相连,而一组相连的网格视为一个水坑。约翰想弄清楚他的田地已经形成了多少水坑。给出约翰田地的示意图,确定当中有多少水坑。

输入第 1行:两个空格隔开的整数:N 和 M。

第 22 行到第 N+1 行:每行 M 个字符,每个字符是 W 或 .,它们表示网格图中的一排。字符之间没有空格。

输出一行,表示水坑的数量。

输入输出样例

输入 

10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.

输出 

3
#include <bits/stdc++.h>
using namespace std;
char a[200][200];
int dx[8]= {-1,-1,-1,0,0,1,1,1},dy[8]= {-1,0,1,-1,1,-1,0,1};
int ans,n,m;
void dfs(int x,int y) {
	a[x][y]='.';
	for(int i=0; i<8; ++i) {
		int xx=x+dx[i];
		int yy=y+dy[i];
		if((xx>=0) && (xx<n) && (yy>=0) && (yy<m) && (a[xx][yy]=='W'))
			dfs(xx,yy);
	}
}
int main() {
	cin>>n>>m;
	for(int i=0; i<=n-1; ++i)
		for(int j=0; j<=m-1; ++j)
			cin>>a[i][j];
	for(int i=0; i<=n-1; ++i)
		for(int j=0; j<=m-1; ++j)
			if(a[i][j]=='W') {
				dfs(i,j);
				ans++;
			}
	cout<<ans;
	return 0;
}

 8.填涂颜色

题目描述(P1162)

由数字 0组成的方阵中,有一任意形状的由数字  构成的闭合圈。现要求把闭合圈内的所有空间都填写成 2。例如:6×6 的方阵(n=6),涂色前和涂色后的方阵如下:

如果从某个 0 出发,只向上下左右 4 个方向移动且仅经过其他 0 的情况下,无法到达方阵的边界,就认为这个 0 在闭合圈内。闭合圈不一定是环形的,可以是任意形状,但保证闭合圈内的 0 是连通的(两两之间可以相互到达)。

0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 1 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 1 2 1
1 1 1 1 1 1

输入格式

每组测试数据第一行一个整数 n(1≤n≤30)。

接下来 n 行,由 0 和 1组成的 n×n 的方阵。

方阵内只有一个闭合圈,圈内至少有一个 0。

输出格式

已经填好数字 2 的完整方阵。

输入输出样例

输入 

6
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1

输出 

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

说明/提示

对于 100% 的数据,1≤n≤30。

#include<bits/stdc++.h>
using namespace std;
int a[100][100],b[100][100]= {0};
int n,x,y;
void dfs(int x,int y) {
	if(x>n||x<1||y>n||y<1||a[x][y]!=0)
		return;
	a[x][y]=1;
	dfs(x+1,y);
	dfs(x-1,y);
	dfs(x,y+1);
	dfs(x,y-1);
}
int main() {
	scanf("%d",&n);
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++) {
			cin>>a[i][j];
			if(a[i][j]==1) 
				b[i][j]=-1;
		}
	int flag=0;
	for(int i=1; i<=n; i++) {
		if(a[i][1]!=1) 
			dfs(i,1);
		if(a[i][n]!=1) 
			dfs(i,n);
	}
	for(int i=1; i<=n; i++) {
		if(a[1][i]!=1) 
			dfs(1,i);
		if(a[n][i]!=1)
			dfs(n,i);
	}
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			if(b[i][j]==-1) 
				printf("1 ");
			else if(a[i][j]==0) 
				printf("2 ");
			else printf("0 ");
		}
		printf("\n");
	}
	return 0;
}

 9.四阶数独

题目描述(T308878)

四阶数独:4*4的格子,每个格子只能写1~4

要求每行、每列、四等分的正方形都正好由1~4组成

问一共有多少种填写方式?

四阶数独的一个例子

输入格式

输出格式

一个整数

10.[USACO1.5] 八皇后 

题目描述(P1219)

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

上面的布局可以用序列2 4 6 1 3 5 来描述,第 ii 个数字表示在第 ii 行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3 个解。最后一行是解的总个数。

输入格式

一行一个正整数 nn,表示棋盘是 n×n 大小的。

输出格式

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

#include<bits/stdc++.h>
using namespace std;
const int N = 16;
int n;
bool col[N * N], dg[N * N], udg[N * N];
int g[N * N], res;
void dfs(int u){
    if (u == n) {
        res ++;
        if (res <= 3){
            for (int  i = 0; i < n; i ++ ) cout << g[i] + 1<< ' ';
            puts("");
            return;
        }
    }
    for (int i = 0; i < n; i ++ ){
        if (!col[i] && !dg[u + i] && !udg[n - u + i]){
            g[u] = i;
            col[i] = dg[u + i] = udg[i - u + n] = true;
            dfs(u + 1);
            col[i] = dg[u + i] = udg[i - u + n] = false;
        }
    }
}
int main(){
    cin >> n;
    dfs(0);
    cout << res << endl;
    return 0;
}

11.马的遍历

题目描述(P1443)

有一个 n×m 的棋盘,在某个点 (x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。

输入格式

输入只有一行四个整数,分别为n,m,x,y。

输出格式

一个 n×m 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 -1)。

输入输出样例

输入 

3 3 1 1

输出 

0    3    2    
3    -1   1    
2    1    4    

说明/提示

数据规模与约定

对于全部的测试点,保证1≤x≤n≤400,1≤y≤m≤400。

#include<bits/stdc++.h>
using namespace std;
struct Node {
	int x,y;
} node;
int n,m,ans[405][405];
queue<Node> Q;
int dx[]= {-1,-1,1,1,-2,-2,2,2};
int dy[]= {-2,2,-2,2,-1,1,-1,1};
bool ok(int x,int y) {
	if(x<1||x>n||y<1||y>m||ans[x][y]>=0)return false;
	return true;
}
void bfs() {
	Q.push(node);
	ans[node.x][node.y]=0;
	while(!Q.empty()) {
		Node s=Q.front();
		Q.pop();

		for(int i=0; i<8; i++) {
			Node t;
			t.x=s.x+dx[i];
			t.y=s.y+dy[i];
			if(ok(t.x,t.y)) {
				Q.push(t);
				ans[t.x][t.y]=ans[s.x][s.y]+1;
			}
		}
	}
}
int main() {
	cin>>n>>m>>node.x>>node.y;
	memset(ans,-1,sizeof(ans));
	bfs();

	for(int i=1; i<=n; i++) {
		for(int j=1; j<=m; j++)printf("%-5d",ans[i][j]);
		cout<<"\n";
	}
	return 0;
}

12.奇怪的电梯

题目描述(P1135)

呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i 层楼(1≤i≤N)上有一个数字 Ki​(0≤Ki​≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如: 3,3,3,1,2,5 代表了 Ki​(K1​=3,K2​=3,……),从 1 楼开始。在1楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有 −2 楼。那么,从 AA楼到 B 楼至少要按几次按钮呢?

输入格式

共二行。

第一行为三个用空格隔开的正整数,表示 N,A,B(1≤N≤200,1≤A,B≤N)。

第二行为 N个用空格隔开的非负整数,表示 Ki​。

输出格式

一行,即最少按键次数,若无法到达,则输出 -1

输入输出样例

输入 

5 1 5
3 3 1 2 5

输出 

3

说明/提示

对于 100% 的数据,1≤N≤200,1≤A,B≤N,0≤Ki​≤N。

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int n,a,b;
int f[205];
int ans[205];
int vis[205];

void dfs(int now,int step) {
	if(step>=ans[now])
		return;
	else
		ans[now]=step;
	if(now==b) {
		return;
	}
	vis[now]=1;
	if(now+f[now]<=n && !vis[now+f[now]])
		dfs(now+f[now],step+1);
	if(now-f[now]>=1 && !vis[now-f[now]])
		dfs(now-f[now],step+1);
	vis[now]=0;
}
int main() {
	ios::sync_with_stdio(false);
	cin>>n>>a>>b;
	for(int i=1; i<=n; i++)
		cin>>f[i];
	memset(ans, 0x3f,sizeof(ans));
	dfs(a,0);
	if(ans[b]!=inf)
		cout<<ans[b]<<endl;
	else
		cout<<-1<<endl;
	return 0;
}

课后作业:

13.  Meteor Shower S

题目描述(P2895)

Bessie hears that an extraordinary meteor shower is coming; reports say that these meteors will crash into earth and destroy anything they hit. Anxious for her safety, she vows to find her way to a safe location (one that is never destroyed by a meteor) . She is currently grazing at the origin in the coordinate plane and wants to move to a new, safer location while avoiding being destroyed by meteors along her way.

The reports say that M meteors (1 ≤ M ≤ 50,000) will strike, with meteor i will striking point (Xi, Yi) (0 ≤ Xi ≤ 300; 0 ≤ Yi ≤ 300) at time Ti (0 ≤ Ti  ≤ 1,000). Each meteor destroys the point that it strikes and also the four rectilinearly adjacent lattice points.

Bessie leaves the origin at time 0 and can travel in the first quadrant and parallel to the axes at the rate of one distance unit per second to any of the (often 4) adjacent rectilinear points that are not yet destroyed by a meteor. She cannot be located on a point at any time greater than or equal to the time it is destroyed).

Determine the minimum time it takes Bessie to get to a safe place.

输入格式

* Line 1: A single integer: M

* Lines 2..M+1: Line i+1 contains three space-separated integers: Xi, Yi, and Ti

输出格式

* Line 1: The minimum time it takes Bessie to get to a safe place or -1 if it is impossible.

题意翻译

题目描述

贝茜听说一场特别的流星雨即将到来:这些流星会撞向地球,并摧毁它们所撞击的任何东西。她为自己的安全感到焦虑,发誓要找到一个安全的地方(一个永远不会被流星摧毁的地方)。

如果将牧场放入一个直角坐标系中,贝茜现在的位置是原点,并且,贝茜不能踏上一块被流星砸过的土地。

根据预报,一共有 M颗流星(1≤M≤50,000) 会坠落在农场上,其中第 i颗流星会在时刻 ( 0≤Ti​≤1000)砸在坐标为 (Xi​,Yi​)(0≤Xi​≤300,0≤Yi​≤300) 的格子里。流星的力量会将它所在的格子,以及周围 44 个相邻的格子都化为焦土,当然贝茜也无法再在这些格子上行走。

贝茜在时刻 0 开始行动,她只能在第一象限中,平行于坐标轴行动,每 1 个时刻中,她能移动到相邻的(一般是 4 个)格子中的任意一个,当然目标格子要没有被烧焦才行。如果一个格子在时刻 tt 被流星撞击或烧焦,那么贝茜只能在 tt 之前的时刻在这个格子里出现。 贝茜一开始在 (0,0)。

请你计算一下,贝茜最少需要多少时间才能到达一个安全的格子。如果不可能到达输出 −1。

输入格式

共M+1 行,第 1 行输入一个整数 M,接下来的 M 行每行输入三个整数分别为 Xi​,Yi​,Ti​。

输出格式

贝茜到达安全地点所需的最短时间,如果不可能,则为 -1。

输入输出样例

输入 

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

输出 

5

14. [NOIP2000 提高组] 单词接龙

题目描述(P1019)

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast 和 astonish,如果接成一条龙则变为 beastonish,另外相邻的两部分不能存在包含关系,例如 at 和 atide 间不能相连。

输入格式

输入的第一行为一个单独的整数 n表示单词数,以下 n行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。

输出格式

只需输出以此字母开头的最长的“龙”的长度。

输入输出样例

输入 

5
at
touch
cheat
choose
tact
a

输出 

23

说明/提示

样例解释:连成的“龙”为 atoucheatactactouchoose。n≤20。

15.[USACO11OPEN] Corn Maze S

题目描述(P1825)

This past fall, Farmer John took the cows to visit a corn maze. But this wasn't just any corn maze: it featured several gravity-powered teleporter slides, which cause cows to teleport instantly from one point in the maze to another. The slides work in both directions: a cow can slide from the slide's start to the end instantly, or from the end to the start. If a cow steps on a space that hosts either end of a slide, she must use the slide.

The outside of the corn maze is entirely corn except for a single exit.

The maze can be represented by an N x M (2 <= N <= 300; 2 <= M <= 300) grid. Each grid element contains one of these items:

* Corn (corn grid elements are impassable)

* Grass (easy to pass through!)

* A slide endpoint (which will transport a cow to the other endpoint)

* The exit

A cow can only move from one space to the next if they are adjacent and neither contains corn. Each grassy space has four potential neighbors to which a cow can travel. It takes 1 unit of time to move from a grassy space to an adjacent space; it takes 0 units of time to move from one slide endpoint to the other.

Corn-filled spaces are denoted with an octothorpe (#). Grassy spaces are denoted with a period (.). Pairs of slide endpoints are denoted with the same uppercase letter (A-Z), and no two different slides have endpoints denoted with the same letter. The exit is denoted with the equals sign (=).

Bessie got lost. She knows where she is on the grid, and marked her current grassy space with the 'at' symbol (@). What is the minimum time she needs to move to the exit space?

输入格式

第一行:两个用空格隔开的整数 NN 和 MM。

第 2∼N+1 行:第i+1 行描述了迷宫中的第 i行的情况(共有M个字符,每个字符中间没有空格)。

输出格式

一个整数,表示起点到出口所需的最短时间。

题意翻译

奶牛们去一个 N×M 玉米迷宫,2≤N≤300,2≤M≤300。

迷宫里有一些传送装置,可以将奶牛从一点到另一点进行瞬间转移。这些装置可以双向使用。

如果一头奶牛处在这个装置的起点或者终点,这头奶牛就必须使用这个装置,奶牛在传送过后不会立刻进行第二次传送,即不会卡在传送装置的起点和终点之间来回传送。

玉米迷宫除了唯一的一个出口都被玉米包围。

迷宫中的每个元素都由以下项目中的一项组成:

  1. 玉米,# 表示,这些格子是不可以通过的。
  2. 草地,. 表示,可以简单的通过。
  3. 传送装置,每一对大写字母 A 到 Z 表示。
  4. 出口,= 表示。
  5. 起点, @ 表示

奶牛能在一格草地上可能存在的四个相邻的格子移动,花费 11 个单位时间。从装置的一个结点到另一个结点不花时间。

输入输出样例

输入 

5 6
###=##
#.W.##
#.####
#.@W##
######

输出 

3

说明/提示

例如以下矩阵,N=5,M=6。

###=##
#.W.##
#.####
#.@W##
######

唯一的一个装置的结点用大写字母 W 表示。

最优方案为:先向右走到装置的结点,花费一个单位时间,再到装置的另一个结点上,花费 0个单位时间,然后再向右走一个,再向上走一个,到达出口处,总共花费了 3 个单位时间。

16.吃奶酪

题目描述(P1433)

房间里放着 n 块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0) 点处。

输入格式

第一行有一个整数,表示奶酪的数量 n。

第 2 到第(n+1) 行,每行两个实数,第(i+1) 行的实数分别表示第 i 块奶酪的横纵坐标 xi​,yi​。

输出格式

输出一行一个实数,表示要跑的最少距离,保留 2 位小数。

输入输出样例

输入 

4
1 1
1 -1
-1 1
-1 -1

输出 

7.41

说明/提示

数据规模与约定

对于全部的测试点,保证1≤n≤15,∣xi​∣,∣yi​∣≤200,小数点后最多有 3 位数字。

提示

对于两个点 (x1​,y1​),(x2​,y2​),两点之间的距离公式为 \sqrt{(x1-x2)^2+(y1-y2)^2}.

17.[NOIP2002 提高组] 字串变换

题目描述(P1032)

已知有两个字串 A,B 及一组字串变换的规则(至多 6 个规则),形如:

  • A1​→B1​。
  • A2​→B2​。

规则的含义为:在 A 中的子串 A1​ 可以变换为 B1​,A2​ 可以变换为 B2​⋯。

例如:A=abcd,B=xyz,

变换规则为:

  • abc→xu,ud→y,y→yz。

则此时,A 可以经过一系列的变换变为 B,其变换的过程为:

  • abcd→xud→xy→xyz。

共进行了 3次变换,使得 A 变换为 B。

输入格式

第一行有两个字符串 A,B。

接下来若干行,每行有两个字符串 Ai​,Bi​,表示一条变换规则。

输出格式

若在 10 步(包含 10步)以内能将 A 变换为 B,则输出最少的变换步数;否则输出 NO ANSWER!

输入输出样例

输入 

abcd xyz
abc xu
ud y
y yz

输出 

3

说明/提示

对于 100% 数据,保证所有字符串长度的上限为 20。

【题目来源】

NOIP 2002 提高组第二题

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值