HDU - 2819 Swap(二分图完备匹配+路径输出)
題目鏈接:點擊查看
題目大意:給出一個n*n的01矩陣,問能否通過數次交換行和列,使得主對角線上的值全部為1
題目分析:因為對角線上的每個元素都對應著不同的一行和一列,換句話說,如果有解,那么肯定可以只移動行或只移動列來完成,如果學了線性代數應該比較好理解了,因為主對角線上全部都為1,所以該矩陣的秩為n,又有定理:任一矩陣可經過有限次初等行變換化成行最簡形矩陣,同理對列也成立
這個時候我們就可以單純的放在行或列上考慮問題了,為了方便書寫習慣,我選擇用列作為轉換目標,此時第一步我們需要理解maze[x][y]的意義,因為我們最終的目標是為了適應所有對角線上的列,所以x代表主對角線上的列,而y代表可以給第x列提供1的列,也就是說maze[x][y]=1代表第x列的1可以由第y列移動而來 ,這樣我們匹配完成后的match[x]代表主對角線上的第x列可以由第match[x]列交換而來,顯然跑完二分圖最大匹配后,若無法構成完備匹配則無解
最后就是比較難想的路徑輸出環節了,因為這個題目的路徑有點奇怪,且樣例給的巨水,這個題目最后要輸出的路徑是:原圖中的某一列x與最終圖中的某一列y的交換,而不是原圖中某兩列交換后形成的新圖,再在新圖上繼續操作而出現的結果,怎么說呢,感覺題目也是為了讓我們方便才這樣規定的,有了這個條件,也就是原圖中的某一列x與最終圖的某一列y交換才是最后的答案,那么我們的目標是將所有的match[x]=x,令1~n的所有等式都成立,模擬整個交換的過程就可以求出路徑了
具體該怎么實現呢?若現在二分圖匹配完成后,我們得到了一組match[i]!=i,我們就需要找到一個j,滿足match[j]=i,這個時候讓第j列和第i列交換,交換后就能滿足match[i]=i了,這樣依次將x與match[x]匹配即可
這個題目的路徑輸出還算是比較巧妙的,算是學到了吧,張見識了
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=110;int n,match[N],vis[N],vis_cnt;bool maze[N][N];bool dfs(int x) {for(int i=1;i<=n;i++)//枚舉每個可以提供貢獻的列 {if(vis[i]!=vis_cnt&&maze[x][i]){vis[i]=vis_cnt;if(!match[i]||dfs(match[i])){match[i]=x;return true;} }}return false; } void init() {vis_cnt=1;memset(vis,false,sizeof(vis)); memset(match,0,sizeof(match));memset(maze,false,sizeof(maze)); }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);while(scanf("%d",&n)!=EOF){init(); for(int i=1;i<=n;i++)//maze[x][y]:第x列的1可以由第y列移動而來 for(int j=1;j<=n;j++)scanf("%d",&maze[i][j]);int ans=0;for(int i=1;i<=n;i++,vis_cnt++)//枚舉主對角線的列 if(dfs(i))ans++;if(ans!=n)puts("-1");else{vector<pair<int,int>>ans;for(int i=1;i<=n;i++)//枚舉對角線的列 {if(i==match[i])//無需交換 continue;for(int j=i+1;j<=n;j++){if(i==match[j]){ans.push_back(make_pair(i,j));swap(match[j],match[i]);break;}}} printf("%d\n",ans.size());for(int i=0;i<ans.size();i++)printf("C %d %d\n",ans[i].first,ans[i].second);}}return 0; }?
總結
以上是生活随笔為你收集整理的HDU - 2819 Swap(二分图完备匹配+路径输出)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1220E T
- 下一篇: HDU - 2389 Rain on y