题目大意
给定一张n个点的无向图,给其加一条边,满足其是二分图。问满足该条件的方案数。
题目传送门:原题链接
解题思路
注意原图不一定连通。
先染色法判断是否为二分图如果有冲突则输出0。可能出现两个二分图同时存在,由于一次只加一条边,
对于不连通的两个二分图节点:
所以可以任意连接两个二分图之间的任意节点,不会产生奇数环故还是二分图。
方案数:(cnt1+cnt2)*(n-cnt1-cnt2)。
由于遍历每个点所以一条无向边会被遍历两次最后要除二 。
对于单个二分图中的节点:
黑白节点各自配对方案数 :cnt1*cnt2。
ac code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int n, m;
int e[3*N], h[N], ne[3*N], idx,color[N];
ll cnt1,cnt2,res1,res2;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool dfs(int k, int c)
{
color[k] = c;
if (c == 1)cnt1++;
else cnt2++;
for (int i = h[k]; i != -1; i = ne[i])
{
int j = e[i];
if (!color[j])
{
if (!dfs(j, 3 - c))return 0;
}
else if(color[j]==c)return 0;
}
return 1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 1; i <=m; i++)
{
int x, y;
cin >> x >> y;
add(x, y); add(y, x);
}
int flag = 1; int cnttt = 0;
for (int i = 1; i <= n; i++)
{
if (!color[i])
{
cnt1 = 0, cnt2 = 0;
if (!dfs(i, 1))
{
flag = 0;
break;
}
res1 += cnt1 * cnt2; //连通图中黑白点配对
res2 += (cnt1 + cnt2) * (n - cnt1 - cnt2);//两个不连通的图配对
}
}
if (!flag)
{
cout << 0 << endl;
return 0;
}
ll ans = res1 + res2 / 2 - m;
cout <<ans << endl;
return 0;
}