YBTOJ:消除格子(二分图匹配)
文章目錄
- 題目描述
- 解析
- 代碼
題目描述
在一個n*n的矩陣中,有 k個格子中有雜物,現在你有一種能力,一次可以消除一行或一列格子中的雜物,問你至少需要幾次可以將這些雜物全部消完。
解析
看起來像是網絡流,結果竟然是二分圖。。。
本題關鍵是模型的轉化,思路有了后就變成板子了
考慮做法:
對于每一個點(x,y)(x,y)(x,y),都連一條從x到y的邊,最后求最大匹配就是答案
為什么是這樣?
首先,這樣連邊之后,每個點對應一條邊,因此每條邊至少要有一個點被選到,因此相當與求這個圖的最小點覆蓋
然后就是兩個很妙的結論:
1.最小點覆蓋=n-最大獨立集
2.最大獨立集=n-最大匹配
為什么?
(網上沒有找到證明,只好自力更生了qwq)
首先,關于性質1,比較簡單:對于任何一個點獨立集SSS,它的補集S′S'S′都是一個合法的點覆蓋(因為根據獨立集的定義,不存在一條邊的兩個端點都在SSS中),那么要使點覆蓋最小,就要使獨立集最大
對于性質2,設全集為M,最大匹配的點集為P,最大獨立集的點集為S,規定一個點集X的大小用|X|表示
那么最大匹配就是∣P∣/2|P|/2∣P∣/2
我們考慮分為兩步證明:∣S∣<=∣M∣?∣P∣/2|S|<=|M|-|P|/2∣S∣<=∣M∣?∣P∣/2 和 ∣S∣>=∣M∣?∣P∣/2|S|>=|M|-|P|/2∣S∣>=∣M∣?∣P∣/2
證畢
有了上面的分析后,本題就變成了一個求最大匹配的板子了
代碼
#include<bits/stdc++.h> using namespace std; const int N=2e6+100; #define ll long long ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();};return x*f; } int n,m; struct node{int to,nxt; }p[N<<1]; int fi[N],cnt=-1; void addline(int x,int y){p[++cnt]=(node){y,fi[x]};fi[x]=cnt; } int mat[N],vis[N]; bool hungry(int x,int tim){if(vis[x]==tim) return false;vis[x]=tim;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(!mat[to]||dfs(mat[to],tim)){mat[to]=x;return true;}}return false; } int main(){memset(fi,-1,sizeof(fi));n=read();m=read();for(int i=1;i<=m;i++){int x=read(),y=read();addline(x,y);}int res=0;for(int i=1;i<=n;i++){if(dfs(i,i)) res++;}printf("%d\n",res);return 0; } /* 3 4 1 1 1 3 2 2 3 2 */總結
以上是生活随笔為你收集整理的YBTOJ:消除格子(二分图匹配)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: YBTOJ洛谷P3195:玩具装箱(斜率
- 下一篇: YBTOJ:幻灯片(二分图匹配)