题意:
给出n个点以及m条边,以及没条边的两个点,求最少添加几条边能得到一个奇环,以及添加边的方法数
解题思路:
添加的边只有四种可能,0,1,2,3
0条边:本身就有奇环 ==> 0 1
2条边:每条边都没有公共点 ==> 2 m*(n-2)
3条边:当且仅当m=0时成立 ==> 3 n*(n-1)*(n-2)/6
比较难搞的就是一条边的时候
用二分图匹配一下
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define ll __int64
#define N 100005
vector<int>vec[N];
int n,m,flag,top;
int p[N],si[N],num[N];
ll ma(int t)
{
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
{
if(p[i]==t) num[si[i]]++;
}
ll ans=0;
for(int i=1;i<=top;i++)
{
ans+=(ll)num[i]*(num[i]-1)/2;
}
return ans;
}
void pa(int u)
{
top++;
si[u] = top;
queue<int>q;
q.push(u);
while(!q.empty())
{
u = q.front();
q.pop();
for(int i=0;i<vec[u].size();i++)
{
int v = vec[u][i];
if(si[v]==0)
{
si[v] = top;
q.push(v);
}
}
}
}
void bfs(int u)
{
queue<int>q;
p[u] = 1;
q.push(u);
while(!q.empty())
{
u = q.front();
q.pop();
for(int i=0;i<vec[u].size();i++)
{
int v = vec[u][i];
if(p[v]==0)
{
p[v] = 3-p[u];
q.push(v);
}
else
{
if(p[v]==p[u]) flag=1;
}
}
}
}
int main()
{
int x,y;
scanf("%d%d",&n,&m);
memset(p,0,sizeof(p));
if(m==0) printf("3 %I64d\n",(ll)n*(n-1)*(n-2)/6);
else
{
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
vec[x].push_back(y);
vec[y].push_back(x);
}
flag=0;
for(int i=1;i<=n;i++)
{
if(p[i]==0) bfs(i);
}
if(flag==1) printf("0 1\n");
else
{
top=0,flag=0;
memset(si,0,sizeof(si));
for(int i=1;i<=n;i++)
{
if(si[i]==0) pa(i);
}
for(int i=1;i<=n;i++)
{
if(vec[i].size()>=2) flag=1;
}
if(flag==0) printf("2 %I64d\n",(ll)m*(n-2));
else
{
printf("1 %I64d\n",(ll)ma(1)+ma(2));
}
}
}
return 0;
}