[CF19E]Fairy

Posted slrslr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF19E]Fairy相关的知识,希望对你有一定的参考价值。

给定一张n个点m条边的无向图,求删除哪一条边后,能够确保构成一个二分图,输出所有可能

 

解法:我们知道二分图的性质是没有奇环,这道题我们也应该从这个方面入手来考虑。

如果没有奇环的话我们当然想怎么删就怎么删,毕竟两个偶环删一条边不会出来一个奇环

如果存在奇环,那么我们删边一定要删奇环上的边,而且这条边必须是所有奇环的并

还要考虑的是,如果这条边还属于某个偶环,删掉这条边后图中还会形成一个新的奇环,因此删除的边还不能属于偶环

这种关于返祖边的题目用树上差分来处理就可以

 

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define M 10010
 5 using namespace std;
 6 struct point{
 7     int from,to,next;
 8 }e[M<<1];
 9 struct Link{
10     int odd,even;
11     bool flag;
12     int from,to;
13 }link[M];
14 int n,m,num,cnt,tot;
15 int  head[M],odd[M],even[M],ans[M],deep[M];
16 bool vis[M];
17 void add(int from,int to)
18 {
19     e[num].next=head[from];
20     e[num].from=from;
21     e[num].to=to;
22     head[from]=num++;
23 }
24 void dfs(int x)
25 {
26     vis[x]=true;
27     for(int i=head[x];~i;i=e[i].next)
28     {
29         int to=e[i].to;
30         if(!vis[to])
31         {
32             link[i>>1].flag=true;
33             deep[to]=deep[x]+1;//树边 
34             dfs(to);
35         }
36     }
37 }
38 void DFS(int x)
39 {
40     vis[x]=true;
41     for(int i=head[x];~i;i=e[i].next)
42     {
43         int to=e[i].to;
44         if(!vis[to])//树边 
45         {
46             DFS(to);
47             odd[x]+=odd[to];
48             even[x]+=even[to];
49             link[i>>1].odd=odd[to];
50             link[i>>1].even=even[to];
51         }
52     }
53 }
54 int main()
55 {
56     memset(head,-1,sizeof(head));
57     scanf("%d%d",&n,&m);
58     for(int i=0;i<m;i++)
59     {
60         scanf("%d%d",&link[i].from,&link[i].to);
61         add(link[i].from,link[i].to); 
62         add(link[i].to,link[i].from);
63     }
64     for(int i=1;i<=n;i++)
65         if(!vis[i])
66         {
67             deep[i]=1;
68             dfs(i);
69         }
70     for(int i=0;i<m;i++)
71     {
72         if(link[i].flag) continue;
73         int u=link[i].from,v=link[i].to;
74         if(deep[u]>deep[v]) swap(u,v);//u为祖先 
75         if((deep[v]-deep[u])&1) even[u]--,even[v]++;
76         else odd[u]--,odd[v]++,link[i].odd++,tot++;
77     }
78     if(!tot)
79     {
80         printf("%d
",m);
81         for(int i=1;i<=m;i++) printf("%d ",i);
82         return 0;
83     }
84     memset(vis,0,sizeof(vis));
85     for(int i=1;i<=n;i++)
86         if(!vis[i])
87             DFS(i);
88     for(int i=0;i<m;i++)
89     {
90         if(link[i].flag)
91         {
92             if(!link[i].even&&link[i].odd==tot) ans[++cnt]=i+1;//是奇环的并且不在偶环上 
93         }
94         else if(tot==1&&link[i].odd) ans[++cnt]=i+1;//如果只有一个奇环,奇环中的边都可删 
95     }
96     printf("%d
",cnt);
97     for(int i=1;i<=cnt;i++) printf("%d ",ans[i]);
98     return 0;
99 }

 

以上是关于[CF19E]Fairy的主要内容,如果未能解决你的问题,请参考以下文章

[CF19E]Fairy

CF 19E Fairy——树上差分

BZOJ4424Cf19E Fairy DFS树

bzoj 4424: Cf19E Fairy && codeforces 19E. Fairy树形dp

bzoj千题计划229:bzoj4424: Cf19E Fairy

CF19 E Fairy——树上差分