A - Oil Deposits
HDU - 1241
1 1 * 3 5 *@*@* **@** *@*@* 1 8 @@****@* 5 5 ****@ *@@*@ *@**@ @@@*@ @@**@ 0 0
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 (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.
4 0 0 2 2 1 2 1 1 2 0 3 5
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
Write a program to count the number of black tiles which he can reach by repeating the moves described above.
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.
6 9 ....#. .....# ...... ...... ...... ...... ...... #@...# .#..#. 11 9 .#......... .#.#######. .#.#.....#. .#.#.###.#. .#.#..@#.#. .#.#####.#. .#.......#. .#########. ........... 11 6 ..#..#..#.. ..#..#..#.. ..#..#..### ..#..#..#@. ..#..#..#.. ..#..#..#.. 7 7 ..#.#.. ..#.#.. ###.### ...@... ###.### ..#.#.. ..#.#.. 0 0
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
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.
1 0 1 2 4 6 7
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.
* 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
* Line 1: A single integer that is the greatest sum of charm desirabilities that can be achieved given the weight constraints
4 6 1 4 2 6 3 12 2 7
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
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!
3 10 110 2 1 1 30 50 10 110 2 1 1 50 30 1 6 2 10 3 20 4
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] + ".");
}
}
}