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

来源:互联网 发布:淘宝小号 浮云网 编辑:程序博客网 时间:2024/06/17 15:27

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

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

练习题如下:

  • POJ 1466: Girls and Boys
  • POJ 3692: Kindergarten
  • POJ 2724: Purifying Machine
  • POJ 2226: Muddy Fields
  • POJ 2251: Merry Christmas

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*011000110 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

阅读全文
1 0