题目:
http://codeforces.com/problemset/problem/557/D题意:
给出一些点和边,要求加上一些边之后得到最小的奇环,求加边的最小数量,及加该数量边时的方法数。思路:
对所有联通分量染色,二分图的思想,当可以染色为二分图时必然只存在偶环,在二分图其中一边随便加入一条边即可,总数为C(sum1,2)+C(sum2,2);
无法染色为二分图则已经存在奇环,无需加边。
另外要加上一些特判,当边数为0时任选3条边组成奇环,总数为C(n,3);
当所有点最多只连接一条边时,加两条边,任选一点加入这两点中,总数为m*(n-2);
代码:
#define N 112345
int n,m;
long long flag,sum,ave,ans,res,hehe;
long long a[N],b[N];
int f[N];
int um[N];
bool vis[N];
vector<int>g[N];
void init()
{
hehe=0;
memset(f,-1,sizeof(f));
memset(vm,0,sizeof(vm));
memset(um,0,sizeof(um));
for(int i=0;i<=n+m;i++)
g[i].clear();
}
void inserts(int u, int v)
{
g[u].push_back(v);
g[v].push_back(u);
}
void dye(int u)
{
int v;
for(int i=0;i<g[u].size();i++)
{
v = g[u][i];
if(f[v]==f[u])
hehe=1;
if(f[v]!=-1)
continue;
f[v] = f[u]^1;
if(f[v])
res++;
else
ans++;
dye(v);
}
}
void Dye()
{
sum=0;
for(int i=1;i<=n;i++)
if(f[i] == -1)
{
f[i] = 0;
res=0;
ans=1;
dye(i);
a[sum]=res;
b[sum]=ans;
sum++;
}
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%d%d",&n,&m)!=EOF&&n)
{
init();
if(m==0)
printf("3 %I64d\n",(long long)n*(n-1)*(n-2)/6);
else
{
for(i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
inserts(x,y);
um[x]++;
um[y]++;
}
flag=1;
for(i=1;i<=n&&flag;i++)
if(um[i]>1)
flag=0;
if(flag)
printf("2 %I64d\n",(long long)m*(n-2));
else
{
Dye();
if(hehe)
{
printf("0 1\n");
continue;
}
res=0;
for(i=0;i<sum;i++)
res+=(a[i]*(a[i]-1)/2+b[i]*(b[i]-1)/2);
printf("%d %I64d\n",1,res);
}
}
}
return 0;
}