题意:给出一个 n 点 m 边的图,问最少加多少边使其能够存在奇环,加最少边的情况数有多少种
奇环和偶环其实就是二分图的性质:二分图不存在奇环,所以只要判断这张图是否是二分图就行了:
如果本身就不是二分图,那么说明图中必定有奇环,那就不需要加边,情况数也就是1种了;
而如果是普通的二分图的话,只要有某一个区块有一半点数大于等于2,那么只要将同一边的任意两点连线,就可以使其不是二分图,从而出现奇环,加边数1条,情况数就是算有多少半点数大于等于2的,从中取两点的情况数;
如果全部都是两点图的话,就要对某个两点图,将两点同时连向其他任意一点,就需要加2条边,情况数就是两点组数乘剩余点数;
最后是全部为单点的图,必须连3条线,将任意三点两两相连,情况数就是任取三点的组合数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h>
2 #include<string.h>
3 #include<algorithm>
4 using namespace std;
5 typedef long long ll;
6
7 int c[100005];
8 int n,m,num[2];
9 int head[100005],nxt[200005],point[200005],size=0;
10 bool f=0;
11
12 void add(int a,int b){
13 point[size]=b;
14 nxt[size]=head[a];
15 head[a]=size++;
16 point[size]=a;
17 nxt[size]=head[b];
18 head[b]=size++;
19 }
20
21 void dfs(int a,int x){
22 if(f)return;
23 c[a]=x;
24 num[x]++;
25 for(int i=head[a];~i;i=nxt[i]){
26 int b=point[i];
27 if(c[b]==-1)dfs(b,!x);
28 else if(c[b]==x){
29 f=1;
30 return;
31 }
32 }
33 }
34
35 int main(){
36 scanf("%d%d",&n,&m);
37 if(m==0){
38 ll ans=(ll)n*(ll)(n-1)*(ll)(n-2)/6;
39 printf("3 %I64d\n",ans);
40 return 0;
41 }
42 int i;
43 memset(head,-1,sizeof(head));
44 memset(c,-1,sizeof(c));
45 for(i=1;i<=m;i++){
46 int a,b;
47 scanf("%d%d",&a,&b);
48 add(a,b);
49 }
50 ll ans=0,ans2=0;
51 for(i=1;i<=n&&(!f);i++){
52 if(c[i]==-1){
53 num[0]=num[1]=0;
54 dfs(i,1);
55 ans+=(ll)num[0]*(ll)(num[0]-1)/2;
56 ans+=(ll)num[1]*(ll)(num[1]-1)/2;
57 if(num[0]==1&&num[1]==1){
58 ans2+=n-2;
59 }
60 }
61 }
62 if(f)printf("0 1\n");
63 else if(ans==0)printf("2 %I64d\n",ans2);
64 else printf("1 %I64d\n",ans);
65 return 0;
66 }