C++ CF862B Mahmoud and Ehab and the bipartiteness
阿新 • • 發佈:2018-11-19
題意翻譯
給出n個點,n-1條邊,求再最多再新增多少邊使得二分圖的性質成立
By @partychicken
(為了儘量更清晰的說明題意,以下為個人附加的內容)
就像這樣(黑邊為原本就有的邊,紅色邊的數量為需要求出的解):
圖片來自:https://www.luogu.org/blog/ACdreamer/solution-cf862b
輸入輸出樣例
輸入樣例1:
3
1 2
1 3
輸出樣例1:
0
輸入樣例2:
5
1 2
2 3
3 4
4 5
輸出樣例2:
2
題目連結: https://www.luogu.org/problemnew/show/CF862B
個人思路:
- 看起來是個二分圖染色的裸題,就可以向二分圖染色的方向進行一些考慮.
- 由於資料不保證給定的圖是聯通圖,所以要準備到圖不是聯通圖的可能。因此,我們要增加一個vis陣列(用於判斷某個點是否被訪問過),並對每個點進行BFS.
- 由題意可知:對於我們要求的結果來說,結果所代表的理想的圖的每一個點,都連線著另一顏色的點集的所有點。根據乘法原理和我們推理所得到的結論,可以得出這樣一個事實:對於結果我們想要推理出的圖來說,她的邊的數量為一種顏色的點的數量*另一種顏色的點的數量.
- 因為我們要求得的結果為:最多需要再新增的邊的數量 因此,我們只需要將求得的邊的總數量再減去圖中一開始就有的邊的數量即可。
- 由此,可得最終結果為:最少(之所以說"最少"是因為給定圖可能不是聯通圖)的一種點的數量*另一種點的數量-n+1.
#include<cstdio> #include<iostream> #include<queue> #include<cstring> using namespace std; const int N=200005,M=200005; long long n,m,cnt=0,head[N],cl[N],vis[N],ansA=0; struct Edge{ int v,w,nxt; }e[M]; void addEdge(int u,int v,int w){ e[++cnt].v=v; e[cnt].w=w; e[cnt].nxt=head[u]; head[u]=cnt; } long long ans[2]{0,0}; int bfs(int x){ queue<int> q; q.push(x); while(!q.empty()){ int nowValue=q.front();q.pop(); for(int i=head[nowValue];i;i=e[i].nxt){ int nowV=e[i].v; if(cl[nowV]==-1){ //cout<<"nowV:"<<nowV<<endl; //cout<<"cl[nowValue]="<<cl[nowValue]<<endl; cl[nowV]=cl[nowValue]^1; //cout<<"cl["<<nowV<<"]="<<cl[nowV]<<endl; ans[cl[nowV]]++; q.push(nowV); } if(cl[nowV]==cl[nowValue]){ return -1; } } } //cout<<"ans[0]:"<<ans[0]<<",ans[1]:"<<ans[1]<<endl; return min(ans[0],ans[1]); } int main(){ memset(cl,-1,sizeof(cl)); scanf("%d",&n); m=n-1; for(int i=1;i<=m;i++){ int ta,tb; scanf("%d%d",&ta,&tb); addEdge(ta,tb,1); addEdge(tb,ta,1); } for(int i=1;i<=n;i++){ if(cl[i]==-1){ cl[i]=1; ans[1]++; //cout<<"bfs:"<<i<<endl; int tempAns=bfs(i); ansA+=ans[0]*ans[1]-n+1; memset(ans,0,sizeof(ans)); } } printf("%lld\n",ansA); return 0; }