挑战程序竞赛系列(27):3.5二分图匹配(2)

挑战程序竞赛系列(27):3.5二分图匹配(2)

详细代码可以fork下Github上leetcode项目,不定期更新。

练习题如下:

POJ 1466: Girls and Boys

活生生的拆散情侣啊,求最大匹配数,接着一刀切,所以答案就是所有学生数减去最大匹配数,当然需要注意addEdge方法,只需要添加一条边即可。因为题目假设情侣们都是两情相悦滴。

代码如下:

import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class Main{
    InputStream is;
    PrintWriter out;
    String INPUT = "./data/judge/201707/1466.txt";

    void solve() {
        while (in.hasNext()){
            int n = in.nextInt();
            init(n);
            for (int i = 0; i < n; ++i){
                in.next();
                String str = in.next();
                int num = Integer.parseInt(str.substring(1, str.length() - 1));
                for (int j = 0; j < num; ++j){
                    int id = in.nextInt();
                    addEdge(i, id);
                }
            }
            int pairs = bipartiteMatching();
            System.out.println(n - pairs);
        }
        in.close();
    }

    //二分图
    List<Integer>[] g;
    int[] matching;
    int V;
    public void init(int n){
        V = n;
        g = new ArrayList[V];
        for (int i = 0; i < V; ++i) g[i] = new ArrayList<Integer>();
        matching = new int[V];
    }


    public void addEdge(int from, int to){
        g[from].add(to);
    }

    public boolean dfs(int v, boolean[] visited){
        visited[v] = true;
        for (int u : g[v]){
            int w = matching[u];
            if (w == -1 || !visited[w] && dfs(w, visited)){
                matching[u] = v;
                matching[v] = u;
                return true;
            }
        }
        return false;
    }

    public int bipartiteMatching(){
        int res = 0;
        Arrays.fill(matching, -1);
        for (int i = 0; i < V; ++i){
            if (matching[i] < 0){
                if (dfs(i, new boolean[V])){
                    res ++;
                }
            }
        }
        return res;
    }

    Scanner in;
    public Main(){
        in = new Scanner(System.in);
    }

    void run() throws Exception {
        solve();
    }

    public static void main(String[] args) throws Exception {
        new Main().run();
    }
}

当然你也可以参考《挑战》P221关于匹配,边覆盖,独立集和顶点覆盖的概念和公式,简单说说。

上述概念都针对一般图,于是有:
(a) 对于不存在孤立点的图,|最大匹配| + |最小边覆盖| = |V|
(b) |最大独立集| + |最小顶点覆盖| = |V|

问题a,求出最大匹配即能求出最小边覆盖,问题b中,针对一般图,求解最大独立集和最小顶点覆盖是NP困难的,但是在二分图中有:
(c) |最大匹配| = |最小顶点覆盖|

所以二分图中能够快速求出最大独立集。

POJ 3692: Kindergarten

思路:可以转换为求补图的最大独立集,而补图恰好是个二分图。二分图的最大独立集 = 总点数 - 二分图最大匹配。于是问题就转换成了求补图的最大匹配了。

证明:补图中的最大独立集,彼此没有边相连,反过来就是彼此都互相连接。

代码如下:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.List;

public class Main{
    InputStream is;
    PrintWriter out;
    String INPUT = "./data/judge/201707/3692.txt";

    void solve() {

        int cnt = 0;
        while (true){
            int G = ni();
            int B = ni();
            int M = ni();
            if (G + B + M == 0) break;
            init(G + B);
            boolean[][] gg = new boolean[G][B];
            for (int i = 0; i < M; ++i){
                int g = ni();
                int b = ni();
                g --;
                b --;
                gg[g][b] = true;
            }
            for (int i = 0; i < G; ++i){
                for (int j = 0; j < B; ++j){
                    if (!gg[i][j]) addEdge(i, j + G);
                }
            }

            out.println("Case " + (++cnt) + ": " + (G + B - bipartiteMatching()));
        }
    }

    //二分图
    List<Integer>[] g;
    int V;
    int[] matching;
    public void init(int n){
        V = n;
        g = new ArrayList[V];
        for (int i = 0; i < V; ++i) g[i] = new ArrayList<Integer>();    
        matching = new int[V];
    }

    public void addEdge(int from, int to){
        g[from].add(to);
        g[to].add(from);
    }

    public boolean dfs(int v, boolean[] visited){
        visited[v] = true;
        for (int u : g[v]){
            int w = matching[u];
            if (w == -1 || !visited[w] && dfs(w, visited)){
                matching[u] = v;
                matching[v] = u;
                return true;
            }
        }
        return false;
    }

    public int bipartiteMatching(){
        int res = 0;
        Arrays.fill(matching, -1);
        for (int i = 0; i < V; ++i){
            if (matching[i] < 0){
                if (dfs(i, new boolean[V])){
                    res ++;
                }
            }
        }
        return res;
    }

    void run() throws Exception {
        is = oj ? System.in : new FileInputStream(new File(INPUT));
        out = new PrintWriter(System.out);

        long s = System.currentTimeMillis();
        solve();
        out.flush();
        tr(System.currentTimeMillis() - s + "ms");
    }

    public static void main(String[] args) throws Exception {
        new Main().run();
    }

    private byte[] inbuf = new byte[1024];
    public int lenbuf = 0, ptrbuf = 0;

    private int readByte() {
        if (lenbuf == -1)
            throw new InputMismatchException();
        if (ptrbuf >= lenbuf) {
            ptrbuf = 0;
            try {
                lenbuf = is.read(inbuf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (lenbuf <= 0)
                return -1;
        }
        return inbuf[ptrbuf++];
    }

    private boolean isSpaceChar(int c) {
        return !(c >= 33 && c <= 126);
    }

    private int skip() {
        int b;
        while ((b = readByte()) != -1 && isSpaceChar(b))
            ;
        return b;
    }

    private double nd() {
        return Double.parseDouble(ns());
    }

    private char nc() {
        return (char) skip();
    }

    private String ns() {
        int b = skip();
        StringBuilder sb = new StringBuilder();
        while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != '
                                    // ')
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }

    private char[] ns(int n) {
        char[] buf = new char[n];
        int b = skip(), p = 0;
        while (p < n && !(isSpaceChar(b))) {
            buf[p++] = (char) b;
            b = readByte();
        }
        return n == p ? buf : Arrays.copyOf(buf, p);
    }

    private char[][] nm(int n, int m) {
        char[][] map = new char[n][];
        for (int i = 0; i < n; i++)
            map[i] = ns(m);
        return map;
    }

    private int[] na(int n) {
        int[] a = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = ni();
        return a;
    }

    private int ni() {
        int num = 0, b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private long nl() {
        long num = 0;
        int b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private boolean oj = System.getProperty("ONLINE_JUDGE") != null;

    private void tr(Object... o) {
        if (!oj)
            System.out.println(Arrays.deepToString(o));
    }
}

POJ 2724: Purifying Machine

题意可参考博文:http://www.hankcs.com/program/algorithm/poj-2724-purifying-machine.html

这台净化机是可以编程的,意味着:

3 3
*01
100
011
0 0

会有:
101,001,100,011
编程:
10* (101, 100)合并而成
0*1 (001, 011)合并而成

所以最少操作为2

那么无非就是尽可能的多构造*,首先把含*的构造成0or1,接着编辑距离为1的两个num建立连接,因为它们可能构成新的*,从而降低操作次数,二分图匹配求最大独立集。

代码如下:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Set;

public class Main{
    InputStream is;
    PrintWriter out;
    String INPUT = "./data/judge/201707/2724.txt";

    void solve() {
        while (true){
            int N = ni();
            int M = ni();
            if (N + M == 0) break;

            Set<Integer> set = new HashSet<Integer>();
            for (int i = 0; i < M; ++i){
                String line = ns();
                if (line.contains("*")){
                    int a1 = 0;
                    int a2 = 0;
                    for (char c : line.toCharArray()){
                        if (c != '*'){
                            a1 |= c - '0';
                            a2 |= c - '0';
                        }
                        else{
                            a1 |= 0;
                            a2 |= 1;
                        }
                        a1 <<= 1;
                        a2 <<= 1;
                    }
                    set.add(a1 >> 1);
                    set.add(a2 >> 1);
                }
                else{
                    int num = 0;
                    for (char c : line.toCharArray()){
                        num |= c - '0';
                        num <<= 1;
                    }
                    set.add(num >> 1);
                }
            }
            Set<Integer> dict = new HashSet<Integer>();
            for (int i = 0, num = 1; i < N; ++i){
                dict.add(num);
                num <<= 1;
            }
            List<Integer> operations = new ArrayList<Integer>(set);
            init(set.size());
            for (int i = 0; i < V; ++i){
                for (int j = i + 1; j < V; ++j){
                    int diff = operations.get(i) ^ operations.get(j);
                    if (dict.contains(diff)){
                        addEdge(i, j);
                    }
                }
            }
            out.println(V - bipartiteMatching());
        }
    }

    //二分图
    List<Integer>[] g;
    int V;
    int[] matching;
    public void init(int n){
        V = n;
        g = new ArrayList[V];
        for (int i = 0; i < V; ++i) g[i] = new ArrayList<Integer>();
        matching = new int[V];
    }

    public void addEdge(int from, int to){
        g[from].add(to);
        g[to].add(from);
    }

    public boolean dfs(int v, boolean[] visited){
        visited[v] = true;
        for (int u : g[v]){
            int w = matching[u];
            if (w == -1 || !visited[w] && dfs(w, visited)){
                matching[u] = v;
                matching[v] = u;
                return true;
            }
        }
        return false;
    }

    public int bipartiteMatching(){
        int res = 0;
        Arrays.fill(matching, -1);
        for (int i = 0; i < V; ++i){
            if (matching[i] < 0){
                if (dfs(i, new boolean[V])){
                    res ++;
                }
            }
        }
        return res;
    }

    void run() throws Exception {
        is = oj ? System.in : new FileInputStream(new File(INPUT));
        out = new PrintWriter(System.out);

        long s = System.currentTimeMillis();
        solve();
        out.flush();
        tr(System.currentTimeMillis() - s + "ms");
    }

    public static void main(String[] args) throws Exception {
        new Main().run();
    }

    private byte[] inbuf = new byte[1024];
    public int lenbuf = 0, ptrbuf = 0;

    private int readByte() {
        if (lenbuf == -1)
            throw new InputMismatchException();
        if (ptrbuf >= lenbuf) {
            ptrbuf = 0;
            try {
                lenbuf = is.read(inbuf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (lenbuf <= 0)
                return -1;
        }
        return inbuf[ptrbuf++];
    }

    private boolean isSpaceChar(int c) {
        return !(c >= 33 && c <= 126);
    }

    private int skip() {
        int b;
        while ((b = readByte()) != -1 && isSpaceChar(b))
            ;
        return b;
    }

    private double nd() {
        return Double.parseDouble(ns());
    }

    private char nc() {
        return (char) skip();
    }

    private String ns() {
        int b = skip();
        StringBuilder sb = new StringBuilder();
        while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != '
                                    // ')
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }

    private char[] ns(int n) {
        char[] buf = new char[n];
        int b = skip(), p = 0;
        while (p < n && !(isSpaceChar(b))) {
            buf[p++] = (char) b;
            b = readByte();
        }
        return n == p ? buf : Arrays.copyOf(buf, p);
    }

    private char[][] nm(int n, int m) {
        char[][] map = new char[n][];
        for (int i = 0; i < n; i++)
            map[i] = ns(m);
        return map;
    }

    private int[] na(int n) {
        int[] a = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = ni();
        return a;
    }

    private int ni() {
        int num = 0, b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private long nl() {
        long num = 0;
        int b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private boolean oj = System.getProperty("ONLINE_JUDGE") != null;

    private void tr(Object... o) {
        if (!oj)
            System.out.println(Arrays.deepToString(o));
    }
}

关于位的操作还不够完美,继续优化。

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Set;

public class Main{
    InputStream is;
    PrintWriter out;
    String INPUT = "./data/judge/201707/2724.txt";

    void solve() {
        while (true){
            int N = ni();
            int M = ni();
            if (N + M == 0) break;

            Set<Integer> set = new HashSet<Integer>();
            for (int i = 0; i < M; ++i){
                String line = ns();
                if (line.contains("*")){
                    int a1 = 0;
                    int a2 = 0;
                    for (char c : line.toCharArray()){
                        a1 <<= 1;
                        a2 <<= 1;
                        if (c != '*'){
                            a1 |= c - '0';
                            a2 |= c - '0';
                        }
                        else{
                            a1 |= 0;
                            a2 |= 1;
                        }
                    }
                    set.add(a1);
                    set.add(a2);
                }
                else{
                    int num = 0;
                    for (char c : line.toCharArray()){
                        num <<= 1;
                        num |= c - '0';
                    }
                    set.add(num);
                }
            }
            List<Integer> operations = new ArrayList<Integer>(set);
            init(set.size());
            for (int i = 0; i < V; ++i){
                for (int j = i + 1; j < V; ++j){
                    int diff = operations.get(i) ^ operations.get(j);
                    if ((diff & (-diff)) == diff){
                        addEdge(i, j);
                    }
                }
            }
            out.println(V - bipartiteMatching());
        }
    }

    //二分图
    List<Integer>[] g;
    int V;
    int[] matching;
    public void init(int n){
        V = n;
        g = new ArrayList[V];
        for (int i = 0; i < V; ++i) g[i] = new ArrayList<Integer>();
        matching = new int[V];
    }

    public void addEdge(int from, int to){
        g[from].add(to);
        g[to].add(from);
    }

    public boolean dfs(int v, boolean[] visited){
        visited[v] = true;
        for (int u : g[v]){
            int w = matching[u];
            if (w == -1 || !visited[w] && dfs(w, visited)){
                matching[u] = v;
                matching[v] = u;
                return true;
            }
        }
        return false;
    }

    public int bipartiteMatching(){
        int res = 0;
        Arrays.fill(matching, -1);
        for (int i = 0; i < V; ++i){
            if (matching[i] < 0){
                if (dfs(i, new boolean[V])){
                    res ++;
                }
            }
        }
        return res;
    }

    void run() throws Exception {
        is = oj ? System.in : new FileInputStream(new File(INPUT));
        out = new PrintWriter(System.out);

        long s = System.currentTimeMillis();
        solve();
        out.flush();
        tr(System.currentTimeMillis() - s + "ms");
    }

    public static void main(String[] args) throws Exception {
        new Main().run();
    }

    private byte[] inbuf = new byte[1024];
    public int lenbuf = 0, ptrbuf = 0;

    private int readByte() {
        if (lenbuf == -1)
            throw new InputMismatchException();
        if (ptrbuf >= lenbuf) {
            ptrbuf = 0;
            try {
                lenbuf = is.read(inbuf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (lenbuf <= 0)
                return -1;
        }
        return inbuf[ptrbuf++];
    }

    private boolean isSpaceChar(int c) {
        return !(c >= 33 && c <= 126);
    }

    private int skip() {
        int b;
        while ((b = readByte()) != -1 && isSpaceChar(b))
            ;
        return b;
    }

    private double nd() {
        return Double.parseDouble(ns());
    }

    private char nc() {
        return (char) skip();
    }

    private String ns() {
        int b = skip();
        StringBuilder sb = new StringBuilder();
        while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != '
                                    // ')
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }

    private char[] ns(int n) {
        char[] buf = new char[n];
        int b = skip(), p = 0;
        while (p < n && !(isSpaceChar(b))) {
            buf[p++] = (char) b;
            b = readByte();
        }
        return n == p ? buf : Arrays.copyOf(buf, p);
    }

    private char[][] nm(int n, int m) {
        char[][] map = new char[n][];
        for (int i = 0; i < n; i++)
            map[i] = ns(m);
        return map;
    }

    private int[] na(int n) {
        int[] a = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = ni();
        return a;
    }

    private int ni() {
        int num = 0, b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private long nl() {
        long num = 0;
        int b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private boolean oj = System.getProperty("ONLINE_JUDGE") != null;

    private void tr(Object... o) {
        if (!oj)
            System.out.println(Arrays.deepToString(o));
    }
}

对于非零的整数,x & (-x)的值就是将其最低位的1独立出来后的值。具体可以参考《挑战》P157.

POJ 2226: Muddy Fields

思路:二分图最小顶点集等于最大匹配数。此二分匹配一定能覆盖所有沼泽,且一个很重要的条件是宽度为1任意长的木板,所以只需要找做左顶点和上顶点构成的木板即可,接着就是问题转换了。

最少木板数,可以理解为被覆盖的沼泽最少,尽可能不去覆盖这样木板数一定是最少的,可现实总是很残酷,总有那么一些沼泽要披上两层木板,此时拿个木钉把横竖木板钉在一块,所使用的钉子最少,就是所求答案。

代码如下:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.List;

public class Main{
    InputStream is;
    PrintWriter out;
    String INPUT = "./data/judge/201707/2226.txt";

    void solve() {
        int R = ni();
        int C = ni();
        char[][] board = new char[R][C];
        for (int i = 0; i < R; ++i){
            for (int j = 0; j < C; ++j){
                board[i][j] = nc();
            }
        }
        init(5000 + 16);
        for (int i = 0; i < R; ++i){
            for (int j = 0; j < C; ++j){
                if (board[i][j] == '*'){
                    int x = i, y = j;
                    while (x > 0 && board[x - 1][j] == '*') x--;
                    while (y > 0 && board[i][y - 1] == '*') y--;
                    addEdge(x * 50 + j, i * 50 + y + 2500);
                }
            }
        }
        out.println(bipartiteMatching());
    }

    //二分图最大匹配等价于最小顶点覆盖
    List<Integer>[] g;
    int V;
    int[] matching;
    public void init(int n){
        V = n;
        g = new ArrayList[V];
        for (int i = 0; i < V; ++i) g[i] = new ArrayList<Integer>();
        matching = new int[V];
    }

    public void addEdge(int from, int to){
        g[from].add(to);
        g[to].add(from);
    }

    public boolean dfs(int v, boolean[] visited){
        visited[v] = true;
        for (int u : g[v]){
            int w = matching[u];
            if (w == -1 || !visited[w] && dfs(w, visited)){
                matching[u] = v;
                matching[v] = u;
                return true;
            }
        }
        return false;
    }

    public int bipartiteMatching(){
        int res = 0;
        Arrays.fill(matching, -1);
        for (int i = 0; i < V; ++i){
            if (matching[i] < 0){
                if (dfs(i, new boolean[V])){
                    res ++;
                }
            }
        }
        return res;
    }

    void run() throws Exception {
        is = oj ? System.in : new FileInputStream(new File(INPUT));
        out = new PrintWriter(System.out);

        long s = System.currentTimeMillis();
        solve();
        out.flush();
        tr(System.currentTimeMillis() - s + "ms");
    }

    public static void main(String[] args) throws Exception {
        new Main().run();
    }

    private byte[] inbuf = new byte[1024];
    public int lenbuf = 0, ptrbuf = 0;

    private int readByte() {
        if (lenbuf == -1)
            throw new InputMismatchException();
        if (ptrbuf >= lenbuf) {
            ptrbuf = 0;
            try {
                lenbuf = is.read(inbuf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (lenbuf <= 0)
                return -1;
        }
        return inbuf[ptrbuf++];
    }

    private boolean isSpaceChar(int c) {
        return !(c >= 33 && c <= 126);
    }

    private int skip() {
        int b;
        while ((b = readByte()) != -1 && isSpaceChar(b))
            ;
        return b;
    }

    private double nd() {
        return Double.parseDouble(ns());
    }

    private char nc() {
        return (char) skip();
    }

    private String ns() {
        int b = skip();
        StringBuilder sb = new StringBuilder();
        while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != '
                                    // ')
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }

    private char[] ns(int n) {
        char[] buf = new char[n];
        int b = skip(), p = 0;
        while (p < n && !(isSpaceChar(b))) {
            buf[p++] = (char) b;
            b = readByte();
        }
        return n == p ? buf : Arrays.copyOf(buf, p);
    }

    private char[][] nm(int n, int m) {
        char[][] map = new char[n][];
        for (int i = 0; i < n; i++)
            map[i] = ns(m);
        return map;
    }

    private int[] na(int n) {
        int[] a = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = ni();
        return a;
    }

    private int ni() {
        int num = 0, b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private long nl() {
        long num = 0;
        int b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private boolean oj = System.getProperty("ONLINE_JUDGE") != null;

    private void tr(Object... o) {
        if (!oj)
            System.out.println(Arrays.deepToString(o));
    }
}

在构图时,遍历当前board是否为”*”,接着把它们定位到最上端和最左端的两块木板,并建立边,形成二分图。

POJ 2251: Merry Christmas

思路:假设L个地方需要L个圣诞老人,那么现在就在此基础上尽可能多的节约圣诞老人。所以说假如知道某个地点的圣诞老人出现的时刻,那么在规定时间内能够抵达另一个地方,那么可以省去一个圣诞老人。最多可以省去多少呢?为最大匹配数,这样此题就转换成了二分图的求解。

代码如下:

    static final int INF = 1 << 28;
    void solve() {
        int[][] distance = new int[100][100];

        while (true){
            int N = ni();
            int M = ni();
            int L = ni();
            if(N == 0 && M == 0 && L == 0) break;

            for (int i = 0; i < 100; ++i){
                Arrays.fill(distance[i], INF);
            }

            for (int i = 0; i < M; ++i){
                int from = ni();
                int to = ni();
                int dis = ni();
                distance[from][to] = dis;
                distance[to][from] = dis;
            }

            for (int k = 0; k < N; ++k){
                distance[k][k] = 0;
                for (int i = 0; i < N; ++i){
                    for (int j = 0; j < N; ++j){
                        distance[i][j] = Math.min(distance[i][j], distance[i][k] + distance[k][j]);
                    }
                }
            }

            int[] p = new int[L];
            int[] t = new int[L];
            for (int i = 0; i < L; ++i){
                p[i] = ni();
                t[i] = ni();
            }

            init(2 * L);
            for (int i = 0; i < L; ++i){
                for (int j = 0; j < L; ++j){
                    if (i != j && t[i] + distance[p[i]][p[j]] <= t[j]){
                        addEdge(2 * i, 2 * j + 1);
                    }
                }
            }
            out.println(L - bipartiteMatching());
        }
    }

    List<Integer>[] g;
    int V;
    int[] matching;
    @SuppressWarnings("unchecked")
    public void init(int n){
        V = n;
        g = new ArrayList[V];
        for (int i = 0; i < V; ++i) g[i] = new ArrayList<Integer>();
        matching = new int[V];
    }

    public void addEdge(int from, int to){
        g[from].add(to);
        g[to].add(from);
    }

    public boolean dfs(int v, boolean[] visited){
        visited[v] = true;
        for (int u : g[v]){
            int w = matching[u];
            if (w == -1 || !visited[w] && dfs(w, visited)){
                matching[u] = v;
                matching[v] = u;
                return true;
            }
        }
        return false;
    }

    public int bipartiteMatching(){
        int res = 0;
        Arrays.fill(matching, -1);
        for (int i = 0; i < V; ++i){
            if (matching[i] < 0){
                if (dfs(i, new boolean[V])){
                    res ++;
                }
            }
        }
        return res;
    }

很奇怪在全数据集上得到的结果都正确,但在AOJ上跑就Runtime Error,有点气人,欢迎找错。

正确AC代码参考:http://www.hankcs.com/program/algorithm/aoj-2251-merry-christmas.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值