- 题目链接:http://codeforces.com/problemset/problem/557/D
- 题意:给你包含n个顶点,m条边的不一定连通&&没有自环和重边的无向图,要你找到能够使得这个图中存在:(奇数长度&&顶点数>1 ) 的简单圈 所需添加边的最小数量t。并且找出添加t的方法数w
- 禁止直接添加自环或重边
- 添加边的方法用所添加边的集合来区分,如果添加的边集相同则认为是同种方法
- 算法:dfs,图论,组合数,数学
- 思路:
- 首先从边界条件开始思考
- 当点的最大连边数=0 时,得t=3, w=n*(n-1)*(n-2)/6
- 当点的最大连边数=1 时,得t=2, w=m*(n-2)
- 当点的最大连边数>=2 时,用dfs判断图中是否有奇数圈,并将每个联通块的顶点陆续标记为1、2;
- 若图中有奇数圈,则t=0, w=1
- 若图中无奇数圈,则t=1, w=每个联通块∑ 【(在所有1号点中取两点的可能数)*(在所有2号点中取两点的可能数)】
#include <bits/stdc++.h>
#define pi acos(-1)
#define fastcin ios::base_sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL ll_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2*1e5 + 10;
const int mod = 1e9 + 7;
int ev[maxn], nxt[maxn], first[maxn];
int esum[maxn], node[maxn];
int cnt, cnt1=0, cnt2=0;
bool dfs_check(int u, int flag)
{
if((node[u]=flag)==1) cnt1++; else cnt2++;
for(int i=first[u]; i!=0; i=nxt[i]){
int v=ev[i];
if(node[v]==0){ if(dfs_check(v, 3-node[u])) return true; }
else{
if(node[u]==node[v]) return true;
}
}
return false;
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for(int i=0; i<m; i++){
int u, v;
scanf("%d%d", &u, &v);
ev[++cnt]=v, nxt[cnt]=first[u], first[u]=cnt; esum[u]++;
ev[++cnt]=u, nxt[cnt]=first[v], first[v]=cnt; esum[v]++;
}
int maxe = 0;
for(int i=1; i<=n; i++) maxe = max(maxe, esum[i]);
if(maxe==0) printf("3 %I64d\n", n*(n-1ll)*(n-2)/6);
else if(maxe==1) printf("2 %I64d\n", m*(n-2ll));
else {
int i=1;
LL ans=0;
for(i=1; i<=n; i++)if(!node[i]){
if(cnt1=cnt2=0, dfs_check(i, 1)) break;
ans += cnt1*(cnt1-1ll)/2 + cnt2*(cnt2-1ll)/2;
}
if(i<=n) printf("0 1\n");
else printf("1 %I64d\n", ans);
}
}