Codeforces-557D Vitaly and Cycle(二分图染色)

来源:互联网 发布:淘宝买家秀 编辑:程序博客网 时间:2024/05/19 17:09

题意:

N个节点,M条边的无向图(不一定连通),问你最少添加多少条边才能找到一个奇圈,并求出相应可行的方法数。

思路:

1. 会发现t只有0,1,2,3四种答案。

2. 当原图构不成二分图时即存在奇数环时直接输出0 1即可;

3. 而当图中不存在边时,则只需要3条边,然后通过画图得到求其种类的方法,感觉这儿挺难找。每次必选一个绿点,然后确定一个点连成直线,再去确定第三个点,然后从图中去掉当前的必选的点,然后再这样进行找即可。如下图:


4. 当图中存在长度大于等于2的连通块时,再通过染色进行寻找,由于是要求构成奇数环,所以同种颜色的点之间连线就可构成一个奇数环。当所有连通块的长度都是2时,更容易做,即通过这唯一一条边去连其它点即可。


代码:

#include <algorithm>#include <string.h>#include <cstdio>#define LL long longusing namespace std;const int maxn = 1e5+5;const int maxm = maxn*2;struct node{int v, next;} edge[maxm];int no, head[maxn];int n, m;int col[maxn];//每个点的颜色LL key[2], flag;//key记录A部和B部的点数,flag用于判断是否构成二分图inline void init(){no = 0; flag = 0;memset(head, -1, sizeof head);memset(col, -1, sizeof col);}inline void add(int u, int v){edge[no].v = v;edge[no].next = head[u];head[u] = no++;}void dfs(int cur, int father, int color){col[cur] = color;++key[color];for(int k = head[cur]; k != -1; k = edge[k].next){if(flag) return;if(edge[k].v == father) continue;if(col[edge[k].v] == color)//连边的两个点属于同一部{flag = 1;return;}if(col[edge[k].v] != -1) continue;dfs(edge[k].v, cur, color^1);}}int main(){int u, v, t; LL w;scanf("%d %d", &n, &m); init();for(int i = 1; i <= m; ++i){scanf("%d %d", &u, &v);add(u, v); add(v, u);}if(m == 0){LL ans = 0, t;for(int i = n-2, j = 1; i >= 1; --i, ++j)ans += (LL)i*j;printf("3 %lld\n", ans);return 0;}t = 2, w = 0;for(int i = 1; i <= n; ++i){if(col[i] != -1) continue;key[0] = key[1] = 0;dfs(i, -1, 1);if(flag){puts("0 1");return 0;}if(key[0]+key[1] < 2) continue;//单个点的连通块直接忽略if(key[0]+key[1] == 2){if(t == 1) continue;w += n-2;}if(key[0]+key[1] > 2){if(t == 2) t = 1, w = 0;if(key[0]) w += (key[0]-1)*key[0]/2;if(key[1]) w += (key[1]-1)*key[1]/2;}}printf("%d %lld\n", t, w);return 0;}

继续加油~

原创粉丝点击