CF #311 D. Vitaly and Cycle 加最少边形成奇圈

题目链接:http://codeforces.com/problemset/problem/557/D

大意 给出一个未必联通的无向图(点数至少为3),问最少加多少边可以形成一个奇圈,以及这样做的方案有多少种。

首先如果是一张没有边的图,那么直接就是需要加三条边,有C(n,3)种方式。

接着,判断这张图每一个联通块是否是一个二分图,因为二分图是一定没有奇圈的。如果有联通块不是二分图,那么也就是意味着存在奇圈,这样的话需要加0条边,方式为1种。

接下去还需要分两种情况讨论

1.如果所有的联通块都只有1个或者2个点,则至少需要加2条边,方式为所有点数为2的联通块随便选择一个其他的点加2条边,故统计所有点数为2的联通块数量。

2.存在至少包含3个点的联通块,注意,此时已经排除了联通块不是二分图的情况,所以也即联通块一定是二分图。对于二分图,连接x部和y部的边是不会形成奇圈的,这种情况下只需要连接一条相同部之间的边即可。所以方案数为对于所有至少包含3个点的联通块,计算x部和y部点数,对答案累加上 C(cntx,2)+C(cnty,2)

 

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 #include <string>
 5 #include <string.h>
 6 #include <stdio.h>
 7 #include <math.h>
 8 #include <stdlib.h>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <set>
13 
14 using namespace std;
15 
16 const int N=1e5+100;
17 
18 vector<int> edge[N];
19 bool vis[N];
20 int col[N];
21 bool found=false;
22 int cnt[2];
23 void dfs(int u,int c) {
24     vis[u]=true;
25     col[u]=c;
26     cnt[c]++;
27     for (int i=0;i<edge[u].size();i++) {
28         int v=edge[u][i];
29         if (vis[v]&&col[v]==c) {
30             found=true;
31         }
32         if (vis[v]) continue;
33         dfs(v,c^1);
34     }
35 }
36 int main(){
37     int n,m;
38     scanf("%d %d",&n,&m);
39     for (int i=1;i<=m;i++) {
40         int u,v;
41         scanf("%d %d",&u,&v);
42         edge[u].push_back(v);
43         edge[v].push_back(u);
44     }
45     if (m==0) {
46         long long ret=1LL*n*(n-1)*(n-2)/6LL;
47         cout<<3<<" "<<ret<<endl;
48     }
49     else {
50         found=false;
51         bool three=false;
52         long long retThree=0;
53         int cnt2=0;
54         for (int i=1;i<=n&&!found;i++) {
55             if (vis[i]) continue;
56             cnt[0]=cnt[1]=0;
57             dfs(i,0);
58             if (cnt[0]+cnt[1]>=3){
59                 three=true;
60                 retThree+=1LL*cnt[0]*(cnt[0]-1)/2LL+1LL*cnt[1]*(cnt[1]-1)/2LL;
61             }
62             else if (cnt[0]+cnt[1]==2)
63                 cnt2++;
64         }
65         if (found) {
66             cout<<0<<" "<<1<<endl;
67         }
68         else if (three){
69             cout<<1<<" "<<retThree<<endl;
70         }
71         else {
72             long long ret=1LL*cnt2*(n-2);
73             cout<<2<<" "<<ret<<endl;
74         }
75     }
76     return 0;
77 }
View Code

 

posted @ 2016-03-23 00:21  活在夢裡  阅读(359)  评论(0编辑  收藏  举报