spoj 3196 Divisibility Relation(最大獨立集輸出方案)

題意:給出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();
	}
}


發佈了75 篇原創文章 · 獲贊 15 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章