题意:给出200个数,选出最大的子集,使得子集中的数相互不整除。
解法:将可以整除的点连边,看上去像是个无向图最大独立集,通过求最大团的办法求解复杂度hold不住。于是观察图的特点,由于整除是一种偏序关系,因此构成的是一个有向无环图,因此也是个二分图(二分图的一个充分必要条件是无奇圈),于是可以转化为求解二分图的最大独立集。具体做法Matrix67给出了证明过程,这篇文章里有http://blog.csdn.net/kksleric/article/details/7465804。
public class Main { int maxn = 210, maxm = 40010; class node { int be, ne; node(int b, int e) { be = b; ne = e; } } class Edmonds { int E[] = new int[maxn], n, m, len; node buf[] = new node[maxm]; int link[] = new int[maxn]; boolean vis[] = new boolean[maxn]; void init(int n, int m) { this.m = m; this.n = n; len = 0; Arrays.fill(E, -1); } void add(int a, int b) { buf[len] = new node(b, E[a]); E[a] = len++; } boolean find(int a) { for (int i = E[a]; i != -1; i = buf[i].ne) { int b = buf[i].be; if (vis[b]) continue; vis[b] = true; if (link[b] == -1 || find(link[b])) { link[b] = a; return true; } } return false; } int solve() { Arrays.fill(link, -1); int ans = 0; for (int i = 1; i <= n; i++) { Arrays.fill(vis, false); if (find(i)) ans++; } return ans; } boolean cv[] = new boolean[maxn + maxn]; void cover() {// 求解最小覆盖集 Arrays.fill(cv, false); for (int i = 1; i <= m; i++) if (link[i] == -1) cv[n + i] = true; boolean end = false; while (!end) { end = true; for (int i = 1; i <= n; i++) { if (cv[i]) continue; boolean flag = false; for (int j = E[i]; j != -1; j = buf[j].ne) { int b = buf[j].be; flag |= cv[b + n]; } if (!flag) continue; cv[i] = true; end = false; for (int j = 1; j <= m; j++) if (link[j] == i) cv[j + n] = true; } } for (int i = 1; i <= m; i++) cv[i + n] = !cv[i + n]; } } Scanner scan = new Scanner(System.in); Edmonds hun = new Edmonds(); int arr[] = new int[maxn], ans[] = new int[maxn]; void run() { int n = scan.nextInt(); int m = scan.nextInt(); hun.init(n, n); while (m-- > 0) { int a = scan.nextInt(); int b = scan.nextInt(); hun.add(Math.min(a, b), Math.max(a, b)); } int res = n - hun.solve(); System.out.println(res); hun.cover(); for (int i = 1; i <= n; i++) if (!hun.cv[i] && !hun.cv[i + n]) { if (--res > 0) System.out.print(i+ " "); else System.out.println(i); } } public static void main(String[] args) throws IOException { new Main().run(); } }