AtCoder Beginner Contest 317 题解 A-E

目录

  • A - Potions
  • B - MissingNo
  • C - Remembering the Days
  • D - President
  • E - Avoid Eye Contact

A - Potions

原题链接

题目描述
有一只生命值为H的怪物,它有N瓶药水,编号为 1 ∼ N 1 \sim N 1N P i < P j , i < j P_i \lt P_j, i \lt j Pi<Pj,i<j),第 i i i 瓶药水可以给怪物恢复 P i P_i Pi点生命值,问怪物喝哪瓶药水可以让 H + P i H+P_i H+Pi最少可以达到X输入那瓶药水的编号

思路:二分

  • P值有序,直接二分
public static void solve() throws IOException{
    int n = readInt(), H = readInt(), X = readInt();
    int[] p = utils.nextIntArray(n);
    int l = 0, r = n + 1;
    while (l + 1 < r) {
        int mid = (l + r) / 2;
        if (p[mid] + H >= X) {
            r = mid;
        } else {
            l = mid;
        }
    }
    printWriter.println(r);
}

B - MissingNo

原题链接

题目描述
N + 1 N+1 N+1个连续的数字,现在给出 N N N个数字,输出缺少的那个数字(答案确保这个数字唯一)。

思路:排序

public static void solve() throws IOException {
    int n= readInt();
    int[] arr = utils.nextIntArray(n);
    Arrays.sort(arr, 1, n + 1);
    int a = arr[1];
    for (int i = 2; i <= n; i++) {
        if (arr[i] != a + 1) {
            printWriter.println(a + 1);
            return;
        }
        a = arr[i];
    }
}

C - Remembering the Days

原题链接

题目描述
N个点,M条双向边,第i条边是点 A i A_i Ai到点 B i B_i Bi的距离,求一个点到另一个点到达的最长距离

样例输入

4 4
1 2 1
2 3 10
1 3 100
1 4 1000

样例输出

1110

思路:dfs

  • 由于数据范围比较小,考虑枚举从每个点出发所能贡献的最大距离。
static int n, m;
static int[][] g;
static boolean[] st;
static long sum = 0;
public static void solve() throws IOException {
    n = readInt(); m = readInt();
    g = new int[n + 1][n + 1];
    while (m-- > 0) {
        int a = readInt(), b = readInt(), c = readInt();
        //双向边
        g[a][b] = Math.max(g[a][b], c);
        g[b][a] = Math.max(g[b][a], c);
    }
    for (int i = 1; i <= n; i++) {
        st = new boolean[n + 1];
        st[i] = true;
        dfs(i, 0);
    }
    printWriter.println(sum);
}

public static void dfs(int x, int curSum) {
    sum = Math.max(sum, curSum);
    for (int i = 1; i <= n; i++) {
    	//这个点 i没有被访问过而且这两个点 i和 x有连边
        if (!st[i] && g[x][i] != 0) {
            st[i] = true;
            dfs(i, curSum + g[x][i]);
            st[i] = false;
        }
    }
}

D - President

原题链接

题目描述
N个选区,第i个选区有 X i + Y i X_i+Y_i Xi+Yi个选民,其中 X i X_i Xi个会给高桥投票, Y i Y_i Yi个会给青木投票,赢得第i个选区会获得 Z i Z_i Zi个席位,谁获得的席位最多,则赢得选举,问最少需要多个选民从青木转到高桥,高桥才会赢

样例输入

2
3 6 2
1 8 5

样例输出

4

思路:01背包

  • 考虑将每一个选区视为一件物品
  • 物品的体积为 Z i Z_i Zi, 物品的价值为 X i ≥ Y i ?   0 : ( Y i − X i + 1 ) / 2 X_i \ge Y_i ? \ 0 : (Y_i - X_i + 1) / 2 XiYi? 0:(YiXi+1)/2
  • dp数组的定义为在总票数为 j时所需要的最少的转向投票的人数
  • 最后再枚举一下总票数超过一半的情况下,需要的最少的转向投票的人数
public static void solve() throws IOException{
    int n = readInt();
    long inf = utils.forceLong(1e18);//注意不能初始化为Long.MAX_VALUE,可能会溢出
    int sum = 0;
    int[] a = new int[n + 1], b = new int[n + 1], c = new int[n + 1];
    for (int i = 1; i <= n; i++) {
        a[i] = readInt(); b[i] = readInt(); c[i] = readInt();
        sum += c[i];
    }
    long[] dp = new long[sum + 1];
    Arrays.fill(dp, inf);
    dp[0] = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = sum; j >= c[i]; j--) {
            dp[j] = Math.min(dp[j], dp[j - c[i]] + (a[i] >= b[i] ? 0 : (b[i] - a[i] + 1) / 2));
        }
    }
    
    int cur = (sum + 1) / 2;
    long res = Long.MAX_VALUE;// 枚举总票数超过一半的情况下,需要的最少的转向投票的人数
    for (int i = cur; i <= sum; i++) {
        res = Math.min(res, dp[i]);
    }
    printWriter.println(res);
}

E - Avoid Eye Contact

原题链接

题目描述
有个NW列的字符矩阵,每个字符的含义如下:

  • .:可通过
  • #:不可通过
  • ^,>,v,<:分别表示有个人朝着上右下左四个方向,无法通过。人的视线沿人面对的方向笔直延伸,并被障碍物或其他人阻挡
  • S:起点,且只有一个,而且不会在他人视线内
  • G:终点,且只有一个,而且不会在他人视线内

样例输入

5 7
....Sv.
.>.....
.......
..<.#<
^G....>

样例输出

15

思路:bfs

  • 先预处理出不能走的点,并将其赋值为!
  • 在bfs一遍找到最短路径
public static void solve() throws IOException {
    int n = readInt(), m = readInt();
    char[][] map = utils.nextCharArray(n, m);
    int sx = -1, sy = -1, ex = -1, ey = -1;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            char ch = map[i][j];
            if (ch == 'S') {
                sx = i; sy = j;
            } else if (ch == 'G') {
                ex = i; ey = j;
            } else if (ch == '^') {
                int p = i - 1;
                //将该点朝上的点赋值为!
                while (p >= 1 && (map[p][j] == '.' || map[p][j] == '!')) {
                    map[p][j] = '!';
                    p--;
                }
            } else if (ch == '>') {
                int p = j + 1;
                //将该点朝右的点赋值为!
                while (p <= m && (map[i][p] == '.' || map[i][p] == '!')) {
                    map[i][p] = '!';
                    p++;
                }
            } else if (ch == '<') {
                int p = j - 1;
                //将该点朝左的点赋值为!
                while (p >= 1 && (map[i][p] == '.' || map[i][p] == '!')) {
                    map[i][p] = '!';
                    p--;
                }
            } else if (ch == 'v') {
                int p = i + 1;
                //将该点朝下的点赋值为!
                while (p <= n && (map[p][j] == '.' || map[p][j] == '!')) {
                    map[p][j] = '!';
                    p++;
                }
            }
        }
    }
    
    Deque<Pair> deque = new LinkedList<>();
    int[][] dist = new int[n + 1][m + 1];
    dist[sx][sy] = 0; map[sx][sy] = '!';
    deque.offer(new Pair(sx, sy));
    while (deque.size() > 0) {
        Pair p = deque.poll();
        for (int i = 0; i < 4; i++) {
            int nx = p.first + dx[i], ny = p.second + dy[i];
            if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && (map[nx][ny] == '.' || map[nx][ny] == 'G')) {
                dist[nx][ny] = dist[p.first][p.second] + 1;
                if (map[nx][ny] == 'G') {
                    printWriter.println(dist[nx][ny]);
                    return;
                }
                map[nx][ny] = '!';
                deque.offer(new Pair(nx, ny));
            }
        }
    }
    printWriter.println(-1);
}

你可能感兴趣的:(深度优先搜索dfs,宽度优先搜索bfs,动态规划dp,算法,java)