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();}}
- hdu 3225 Flowers Placement(字典序第k小的完美匹配)
- HDU 3225 Flowers Placement 二分图第k优解
- hdu 3225 Flowers Placement 二分图匹配+dfs
- hdu(3225) 求第k小匹配(09上海站F题)
- uva 1459 - Flowers Placement(二分图匹配+暴力)
- SPOJ 7258 字典序第K小的子串:后缀自动机
- HDU 3020 Antenna Placement(二分图匹配)
- 【HDU】2665 求第k小的数
- HDU 3949 XOR (第k小的异或值)
- 模拟之全排列的第k个字典序
- HDU 4006 第K大元素(小技巧)
- 第k个字典序全排列(kth permutation)
- UVA 1262编码(第k字典序)
- 第k个字典序全排列
- 第k小的元素
- 第k小的数
- 第k小的数
- leetcode 440. K-th Smallest in Lexicographical Order 第k个字典序的数字
- Metro 风格应用的导航设计
- 教你巧记 java 23种设计模式
- svn全局忽略样式
- 通向架构师的道路(第三天)之apache性能调优
- 只允许启动个一个进程
- hdu 3225 Flowers Placement(字典序第k小的完美匹配)
- Servlet中forward和redirect的区别
- Android开发 返回键的复写 onBackPressed()
- tomcat7 远程 DEBUG
- oracle partition 的增加和销毁
- 对于vector第一个元素访问的几种方法
- 念,心随君浅舞天涯
- jsp简单上传
- 新浪微博错误代码详解