hdu 3225 Flowers Placement(字典序第k小的完美匹配)

来源:互联网 发布:js中的event中target 编辑:程序博客网 时间:2024/06/01 12:03

题意:用n个元素填满一个m行n列的矩阵,使得每行和每列中每个元素仅出现一次,现要再添加一行,使得矩阵仍满足上述限制,问字典序第k大的方案是什么.

解法:错误的解法是填k次,每次填最小的,若仍存在解则第k次的填充方案就是字典序第k小的,例如原有1234,第一次填2143第二次填3412不死后第二小的。

朴素的做法的dfs全排列然后验证,这样显然复杂度太高,于是考虑利用二分匹配剪枝:当递归到第i层,即第i列填充上某个元素x后,若x之后的位置和剩余的元素不能形成完美匹配则不必继续向下递归,这样验证的复杂度为O(VE);

继续简化,模拟一下过程:当i为占用了x,则原来占用x的位置j需要找到另外一个元素y,原来占用y的位置需要找到另外一个元素z。。。直到某个位置找到了i释放的元素,因此就是从j出发找一条增广路,且增广路不能经过左侧小于等于i的点(因为那些已经构成字典序了),若曾在这样一条增广路则说明i位置可以取x,否则直接剪枝,验证的复杂度为O(E)。

import java.util.Arrays;import java.util.Scanner;public class Flower3225 {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][maxn], n, m, len;int link[] = new int[maxn];boolean vis[] = new boolean[maxn];void init(int n, int m) {this.m = m;this.n = n;len = 0;for (int i = 1; i <= n; i++)Arrays.fill(E[i], 0);}boolean find(int a,int lim) {if(a<=lim)return false;for (int i = 1; i <= m; i++) {if (E[a][i] == 0 || vis[i])continue;vis[i] = true;if (link[i] == -1 || find(link[i],lim)) {link[i] = 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,0))ans++;}return ans;}int lk[]=new int[maxm];boolean check(int p,int v){if(link[v]==p)return true;for(int i=1;i<=m;i++)lk[i]=link[i];for(int i=1;i<=m;i++)if(link[i]==p)link[i]=-1;int temp=link[v];link[v]=p;Arrays.fill(vis, false);if(find(temp,p))  return true;for(int i=1;i<=m;i++)link[i]=lk[i];return false;}}Scanner scan = new Scanner(System.in);Edmonds hun = new Edmonds();int map[][] = new int[maxn][maxn], vis[] = new int[maxn],ans[] = new int[maxn];int n, m, k, cnt;void work() {hun.init(n, n);for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)hun.E[i][j] = map[i][j];Arrays.fill(vis, 0);cnt = 0;hun.solve();if (!dfs(1))System.out.println(-1);}boolean dfs(int d) {if (d > n) {cnt++;if (cnt < k)return false;for (int i = 1; i < n; i++)System.out.print(ans[i] + " ");System.out.println(ans[n]);return true;}for (int i = 1; i <= n; i++)if (map[d][i] == 1 && vis[i] == 0 && hun.check(d, i)) {vis[i] = 1;ans[d] = i;if (dfs(d + 1))return true;vis[i] = 0;}return false;}void run() {int cas = scan.nextInt();for (int c = 1; c <= cas; c++) {System.out.print("Case #" + c + ": ");n = scan.nextInt();m = scan.nextInt();k = scan.nextInt();for (int i = 1; i <= n; i++)Arrays.fill(map[i], 1);for (int i = 1; i <= m; i++)for (int j = 1; j <= n; j++)map[j][scan.nextInt()] = 0;work();}}public static void main(String[] args) {new Flower3225().run();}}


原创粉丝点击