sduacm16级寒假训练 搜索与背包

A - Oil Deposits

  HDU - 1241            

 

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


package A;
/*
 * 题目大意:油井勘探,给出一个m x n的油田,@代表有油田,*代表无,adjacent(毗邻的,相邻的)@算同一块油田,问一共有多少不同的油田。
 * 0代表输入结束。
 * 解题思路:DFS
 */
import java.util.*;

public class Main {
	static int m, n;
	static char arrs[][];

	static void dfs(int x,int y){
		arrs[x][y] = '*';          //走过的直接改成*
		for(int dx = -1;dx<=1;dx++){
			for(int dy = -1;dy<=1;dy++){       //通过循环得到八个方向
				int nx = x+dx,ny = y+dy;
				if(nx>=0&&nx<m&&ny>=0&&ny<n&&arrs[nx][ny]=='@')
					dfs(nx,ny);
			}
		}
		return;
	}

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while (sc.hasNext()) {
			m = sc.nextInt();
			n = sc.nextInt();
			if (m==0||n==0) {
				return;
			}
			arrs = new char[m][n];
			for (int i = 0; i < m; i++) {
//				String blank = sc.nextLine();
				String str = sc.next();
				for (int j = 0; j < n; j++)
					arrs[i][j] = str.charAt(j);
			}
			int count = 0;
			for (int i = 0; i < m; i++) {
				for (int j = 0; j < n; j++) {   //遍历,找到@进行dfs,进行一个dfs算作一个油田
					if (arrs[i][j] == '@') {
						dfs(i,j);
						count++;
					}
				}
			}
			System.out.println(count);
		}

	}

}

B - Meteor Shower

  POJ - 3669 


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 (XiYi) (0 ≤ X≤ 300; 0 ≤ Y≤ 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.

Input

* Line 1: A single integer: M
* Lines 2..M+1: Line i+1 contains three space-separated integers: XiYi, and Ti

Output

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

Sample Input
4
0 0 2
2 1 2
1 1 2
0 3 5
Sample Output
5

package B;
/*
 * 题目大意:流星雨要来啦,一个人开车逃命,M颗流星雨,每一颗都在Ti时刻砸在(xi,yi),毁坏范围包括该点及其直线方向毗邻的点
 * 求顺利逃脱的最小时间,不能逃脱输出-1,所有活动范围(x>=0,y>=0)
 * 解题思路:维护一个map,map上bfs,考虑边界,一开始数组就开小了
 */
import java.util.*;

class point {
	int x, y, t;

	public point(int x, int y, int t) { // 初始化点 加坐标和时间属性
		this.x = x;
		this.y = y;
		this.t = t;
	}
}

public class Main {
	static int M; // 点的个数
	static point[] ms = new point[100000]; // 储存点 
	static boolean flag = false;
	static int res;
	static int[][] visited = new int[302][302]; // 标记走过的点
	static int[][] map = new int[302][302]; // meteors危及的点的map
	static int[][] dir = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } }; // direction
	static int t;

	static int bfs(int x, int y) {           //对于bfs的掌握明显不如dfs!
		Queue<point> q = new LinkedList<point>();
		point p1 = new point(0, 0, 0);
		q.add(p1);
		visited[p1.x][p1.y] = 1; // 访问过初始点
		while (!q.isEmpty()) {
			// count++;
			point temp = q.peek(); // 指向队头
			q.poll(); // 第一个出队
			if (temp.t >= map[temp.x][temp.y]) // 重叠部分取小的计算,大的直接continue
				continue;
			for (int i = 0; i < 4; i++) {
				int tx = temp.x + dir[i][0]; // 循环遍历方向
				int ty = temp.y + dir[i][1];
				t = temp.t + 1; // 更新当前时间
				if (0 <= tx && 0 <= ty && visited[tx][ty] != 1 && map[tx][ty] == 10000) { // 走到了安全地方
					return t;
				} else if (0 <= tx && 0 <= ty && visited[tx][ty] != 1 && t < map[tx][ty]) { // 未访问并且来得及
					point p2 = new point(tx, ty, t);
					q.add(p2);
					visited[tx][ty] = 1; // 更新访问点
				}
			}
		}
		return -1;
	}

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		while (sc.hasNext()) {

			for (int i = 0; i < 100000; i++)
				ms[i] = new point(0, 0, 10000); //初始化时间
			for (int i = 0; i < 302; i++) {
				for (int j = 0; j < 302; j++) { // 初始化map和visited
					map[i][j] = 10000; // meteor砸落先为10000 访问1 未访问0
					visited[i][j] = 0;
				}
			}
			M = sc.nextInt();
			for (int i = 0; i < M; i++) { // 读入 坐标和时间
				ms[i].x = sc.nextInt();
				ms[i].y = sc.nextInt();
				ms[i].t = sc.nextInt();
			}
			for (int i = 0; i < M; i++) {
				if (map[ms[i].x][ms[i].y] == 10000) // 初始化map时间
					map[ms[i].x][ms[i].y] = ms[i].t;
				for (int j = 0; j < 4; j++) {
					int tx = ms[i].x + dir[j][0]; // 四个方向
					int ty = ms[i].y + dir[j][1];
					if (0 <= tx && 0 <= ty && map[tx][ty] >= ms[i].t) // 范围内初始化砸落时间
																		// 取先砸落赋值
						map[tx][ty] = ms[i].t;
				}
			}
			// count = -1;
//			flag = false;
			
//			if (flag)
				System.out.println(bfs(0, 0));
//			else
//				System.out.println(-1);

		}

	}

}


C - Red and Black

  POJ - 1979 



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) 
The end of the input is indicated by a line consisting of two zeros. 
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


package C;
/*
 * 题目大意:给一个W列H行的矩阵,.代表黑瓦 #代表红瓦@是起点,一个人只有四个方向并且只能走黑瓦,求能走多少块黑瓦。0 0 输入结束
 * 解题思路:dfs
 */
import java.util.*;
public class Main {
	static int W,H;
	static char [][]tiles;
	static int count;
	static int markH,markW;
	static void dfs(int y,int x){
		tiles[y][x]='#';    //走过的都变成# 避免重复访问
		count++;
		if(y-1>=0&&y-1<H&&x>=0&&x<W&&tiles[y-1][x]=='.')  //四个方向
			dfs(y-1,x);
		if(y+1>=0&&y+1<H&&x>=0&&x<W&&tiles[y+1][x]=='.')
			dfs(y+1,x);
		if(y>=0&&y<H&&x-1>=0&&x-1<W&&tiles[y][x-1]=='.')
			dfs(y,x-1);
		if(y>=0&&y<H&&x+1>=0&&x+1<W&&tiles[y][x+1]=='.')
			dfs(y,x+1);
	}

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			count = 0;
			W = sc.nextInt();H = sc.nextInt();
			if(W==0) return;
			tiles = new char[H][W];
			for(int i = 0;i<H;i++){
				String str = sc.next();
				for(int j = 0;j<W;j++){
					tiles [i][j] = str.charAt(j);
					if(tiles[i][j]=='@'){
						markH = i;markW = j;
					}
				}
			}
			dfs(markH,markW);
			System.out.println(count);
		}

	}

}

D - Smallest Difference

  POJ - 2718 



iven a number of distinct decimal digits, you can form one integer by choosing a non-empty subset of these digits and writing them in some order. The remaining digits can be written down in some order to form a second integer. Unless the resulting integer is 0, the integer may not start with the digit 0. 

For example, if you are given the digits 0, 1, 2, 4, 6 and 7, you can write the pair of integers 10 and 2467. Of course, there are many ways to form such pairs of integers: 210 and 764, 204 and 176, etc. The absolute value of the difference between the integers in the last pair is 28, and it turns out that no other pair formed by the rules above can achieve a smaller difference.
Input
The first line of input contains the number of cases to follow. For each case, there is one line of input containing at least two but no more than 10 decimal digits. (The decimal digits are 0, 1, ..., 9.) No digit appears more than once in one line of the input. The digits will appear in increasing order, separated by exactly one blank space.
Output
For each test case, write on a single line the smallest absolute difference of two integers that can be written from the given digits as described by the rules above.
Sample Input
1
0 1 2 4 6 7
Sample Output
28

package D;
/*
 * 题目大意:多组数据,每组数据输入一行递增数字(0-9),组成两个整数使得两者差的绝对值最小
 * 解题思路:奇数个数字的情况下直接四位数min三位数max即可,偶数个数字则进行遍历,逐个比较取min。
 */
import java.util.*;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int T = sc.nextInt();
		String blank = sc.nextLine();
		for (int a = 0; a < T; a++) {
			int[] n = new int[10];
			int count = 0;
			int res = 1000000;
			String str = sc.nextLine();
			int index = 0;
			for (int i = 0; i <= str.length() - 1; i++) {
				if (i % 2 == 0) {
					n[index] = Integer.parseInt(str.charAt(i)+"");
					if (n[index] == 0)
						count++;
					if (n[index] != 0)
						count++;
					index++;
				}
			}
			if (count == 2) {                  //特别考虑两个数字的情况! wa...
				System.out.println(n[1]-n[0]);
			} else if (count % 2 == 1) {                       //odd
				int num1 = 0, num2 = 0;
				if(n[0]==0){                    //0或0非0讨论取出最小的四位数
						num1 = n[1]*10;
						for(int i = 2;i<=count/2;i++)
							num1 = num1*10+n[i];
				}else{
					for(int i = 0;i<=count/2;i++)
						num1 = num1*10+n[i];
				}
				for (int i = count- 1; i >count/2; i--) {
					num2 = num2 * 10 + n[i];            //最大三位数
				}
				System.out.println(num1 - num2);
			} else {                                       //even
				int counter = 0;
				for (int i = 0; i < count - 1; i++) {
					if (n[i] == 0)
						continue;
					int num1 = n[i], num2 = n[i + 1]; // num2第一个数字较大 所以后面的数字取小的
					counter = 0;
					for (int j = count - 1; j >= 0; j--) {
						if (j != i && j != i + 1 && counter < (count - 2) / 2){
							num1 = num1 * 10 + n[j];counter++;                  //num1剩余数字倒着取,保证取到大的数
						}
					}
					counter = 0;     //这里用了一个counter控制长度
					for (int j = 0; j < count - 1; j++) {                  //num2正着取,保证取到小的
						if (j != i && j != i + 1 && counter < (count - 2) / 2){
							num2 = num2 * 10 + n[j];counter++;
						}
					}
					if (Math.abs(num2 - num1) < res)   //更新res
						res = Math.abs(num2 - num1);
				}
				System.out.println(res);
			}

		}
	}

}


E - Charm Bracelet

  POJ - 3624   


Bessie has gone to the mall's jewelry store and spies a charm bracelet. Of course, she'd like to fill it with the best charms possible from the N (1 ≤ N ≤ 3,402) available charms. Each charm i in the supplied list has a weight Wi (1 ≤ Wi ≤ 400), a 'desirability' factor Di (1 ≤ Di ≤ 100), and can be used at most once. Bessie can only support a charm bracelet whose weight is no more than M (1 ≤ M ≤ 12,880).

Given that weight limit as a constraint and a list of the charms with their weights and desirability rating, deduce the maximum possible sum of ratings.

Input

* Line 1: Two space-separated integers: N and M
* Lines 2..N+1: Line i+1 describes charm i with two space-separated integers: Wi andDi

Output

* Line 1: A single integer that is the greatest sum of charm desirabilities that can be achieved given the weight constraints

Sample Input
4 6
1 4
2 6
3 12
2 7
Sample Output
23


package E;
/*
 * 题目大意:N个珠宝,容量M的背包,输入每个珠宝的weight和value,输出最大的value值。
 * 解题思路:01背包  状态转移方程:f[i] = max(f[i],f[i-wi]+vi)
 */
import java.util.*;
public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			int N = sc.nextInt(),weight = sc.nextInt();
			int [] wei = new int[N];
			int [] val = new int[N];
			for(int i = 0;i<N;i++){
				wei[i] = sc.nextInt();val[i] = sc.nextInt();
			}
			int bag[] = new int[weight+1];
			for(int i = 0;i<N;i++){
				for(int j = weight;j>=wei[i];j--){      //01背包一维数组实现是倒着选的,j从weight开始。
//首先想想为什么01背包中要按照v=V..0的逆序来循环。这是因为要保证第i次循环中的状态f[v]是由状态f[v-c]递推而来。
//换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个没有已经选入第i件物品的子结果f[v-c[i]]。
//而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[v-c],
//所以就可以并且必须采用v=0..V的顺序循环。这就是这个简单的程序为何成立的道理。
					if(bag[j]<(bag[j-wei[i]]+val[i]))
						bag[j] = bag[j-wei[i]]+val[i];
					else
						bag[j] = bag[j];
				}
			}
			System.out.println(bag[weight]);
		}

	}

}

F - Piggy-Bank

  POJ - 1384 


Before ACM can do anything, a budget must be prepared and the necessary financial support obtained. The main income for this action comes from Irreversibly Bound Money (IBM). The idea behind is simple. Whenever some ACM member has any small money, he takes all the coins and throws them into a piggy-bank. You know that this process is irreversible, the coins cannot be removed without breaking the pig. After a sufficiently long time, there should be enough cash in the piggy-bank to pay everything that needs to be paid. 

But there is a big problem with piggy-banks. It is not possible to determine how much money is inside. So we might break the pig into pieces only to find out that there is not enough money. Clearly, we want to avoid this unpleasant situation. The only possibility is to weigh the piggy-bank and try to guess how many coins are inside. Assume that we are able to determine the weight of the pig exactly and that we know the weights of all coins of a given currency. Then there is some minimum amount of money in the piggy-bank that we can guarantee. Your task is to find out this worst case and determine the minimum amount of cash inside the piggy-bank. We need your help. No more prematurely broken pigs! 
Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing two integers E and F. They indicate the weight of an empty pig and of the pig filled with coins. Both weights are given in grams. No pig will weigh more than 10 kg, that means 1 <= E <= F <= 10000. On the second line of each test case, there is an integer number N (1 <= N <= 500) that gives the number of various coins used in the given currency. Following this are exactly N lines, each specifying one coin type. These lines contain two integers each, Pand W (1 <= P <= 50000, 1 <= W <=10000). P is the value of the coin in monetary units, W is it's weight in grams.
Output
Print exactly one line of output for each test case. The line must contain the sentence "The minimum amount of money in the piggy-bank is X." where X is the minimum amount of money that can be achieved using coins with the given total weight. If the weight cannot be reached exactly, print a line "This is impossible.".
Sample Input
3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4
Sample Output
The minimum amount of money in the piggy-bank is 60.
The minimum amount of money in the piggy-bank is 100.
This is impossible.

package F;
/*
 * 题目大意:T组数据,每组给出存钱罐的重量E和装满硬币的重量F以及每种硬币的面值P和重量W,求出钱最少的情况。
 * 如果重量不可能实现输出一句话。
 * 解题思路:完全背包,max改成min  f[i] = min(f[i],f[i-W]+P)
 */
import java.util.*;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int T = sc.nextInt();
		for (int ds = 0; ds < T; ds++) {
			int empty = sc.nextInt(), filled = sc.nextInt();
			int weight = filled - empty;
			int type = sc.nextInt();
			int[] pri = new int[type], wei = new int[type];
			for (int i = 0; i < type; i++) {
				pri[i] = sc.nextInt();
				wei[i] = sc.nextInt();
			}
			int bag[] = new int[weight + 1];
			for (int i = 1; i < weight + 1; i++)
				bag[i] = 10000000;              //初始化为较大值
			bag[0] = 0;

			for (int i = 0; i < type; i++) {
				for (int j = wei[i]; j <= weight; j++) {       //完全背包从0开始,根据实际意义,从wei[i]开始。
					if (bag[j] < (bag[j - wei[i]] + pri[i]))
						bag[j] = bag[j];
					else
						bag[j] = bag[j - wei[i]] + pri[i];
				}
			}
			if (bag[weight] == 10000000)
				System.out.println("This is impossible.");
			else
				System.out.println("The minimum amount of money in the piggy-bank is " + bag[weight] + ".");

		}

	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值