题意:给出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();
}
}