[BZOJ 1143] 祭祀river
阿新 • • 發佈:2018-05-27
col ++ code ive 匹配 最大 長度 AI ron
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1143
Solution:
一道最長反鏈的模板題
由Dilworth定理可知:最小鏈覆蓋數(偏序集能劃分成的最少的全序集的個數) = 最長反鏈長度
其對偶定理:最長鏈長度 = 最小反鏈覆蓋數
(VFleaking的證明:http://vfleaking.blog.163.com/blog/static/1748076342012918105514527/)
求解最小鏈覆蓋的方式:
1、先用Floyd求出傳遞閉包,表示哪些(x,y)間是可以相互抵達的
2、將每個點拆分,最小鏈覆蓋=n-二分圖最大匹配
證明:每匹配兩個點,則意味著少了一條鏈,從而最少鏈的數量為n-最大匹配的數量
而先計算傳遞閉包是為了實現路徑的可交叉,相當於“跳過”交叉點進行匹配
Code:
#include <bits/stdc++.h> using namespace std; const int MAXN=105; int n,m,x,y,match[MAXN*2],f[MAXN][MAXN],vis[MAXN*2]; bool dfs(int x) { for(int i=1;i<=n;i++) if(f[x][i] && !vis[i]) { vis[i]=true; if(match[i]==-1 || dfs(match[i])) { match[i]=x; return true; } } return false; } int main() { cin >> n >> m; for(int i=1;i<=m;i++) cin >> x >> y,f[x][y]=1; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]|=f[i][k]&&f[k][j]&&!(i==j); memset(match,-1,sizeof(match)); int res=n; for(int i=1;i<=n;i++) memset(vis,0,sizeof(vis)),res-=dfs(i); for(int i=1;i<=n;i++) cout << match[i] << " "; cout << endl; cout << res; return 0; }
Review:
1、最小鏈覆蓋(交叉/不交叉)的求法
2、記住將i=j的f[i][j]設為0
[BZOJ 1143] 祭祀river