hdu5215 求无向图中是否有奇环和偶环 :lca+dfs使图->树

队友给的思路,感觉思路很好啊==

对图进行dfs扫描,假设u->v,遇到已经扫过的点v,计算当前点u和v的lca,lca和u以及v之间形成了一个环(计算奇偶)

这样只能计算有没有简单的奇偶环,比如两个简单的奇环在一起就成了偶环(无论两个奇环共享几条边)

所以在dfs中扫完子树之后,看有没有找到过两个奇环,如果奇环>=4就有了一个偶环(双向边,等价于两个奇环)

具体实现可以见代码==

  1 #pragma comment(linker, "/STACK:102400000,102400000")
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<algorithm>
  5 #define maxn 100005
  6 #define maxm 600005
  7 using namespace std;
  8 int Now,Next[maxm],Head[maxm],Point[maxm];
  9 int parent[maxn][25],depth[maxn];
 10 int ans1,ans2,vis[maxn];
 11 void Add(int u,int v)
 12 {
 13   Next[++Now]=Head[u];
 14   Head[u]=Now;
 15   Point[Now]=v;
 16 }
 17 void dfs1(int u,int pre,int deep)
 18 {
 19   vis[u]=1;
 20   parent[u][0]=pre;
 21   depth[u]=deep;
 22   for (int i=Head[u];i;i=Next[i])
 23   {
 24     int v=Point[i];
 25     if (v==pre||vis[v]) continue;
 26     dfs1(v,u,deep+1);
 27   }
 28 }
 29 void double_build(int n)
 30 {
 31   int i,j;
 32   for (i=0;i<20;i++)
 33     for (j=1;j<=n;j++)
 34       if (parent[j][i]<=0) parent[j][i+1]=0;
 35       else parent[j][i+1]=parent[parent[j][i]][i];
 36 }
 37 int lca(int u,int v)
 38 {
 39   int i;
 40   if (depth[u]>depth[v]) swap(u,v);
 41   for (i=0;i<=20;i++)
 42     if ((depth[v]-depth[u])>>i&1)
 43       v=parent[v][i];
 44   if (u==v) return u;
 45   for (i=20;i>=0;i--)
 46     if (parent[u][i]!=parent[v][i])
 47     {
 48       u=parent[u][i];
 49       v=parent[v][i];
 50     }
 51   return parent[u][0];
 52 }
 53 void solve(int u,int v)
 54 {
 55   int fa=lca(u,v);
 56   int tmp=depth[u]+depth[v]-2*depth[fa]+1;
 57   if (tmp%2) ans1++;
 58   else ans2++;
 59 }
 60 void dfs2(int u,int pre)
 61 {
 62   int i,v;
 63   vis[u]=1;
 64   for (i=Head[u];i;i=Next[i])
 65   {
 66     v=Point[i];
 67     if (v==pre) continue;
 68     if (vis[v]) solve(u,v);
 69     else dfs2(v,u);
 70   }
 71   if (ans1>=4) ans2++; //thinking
 72 }
 73 int main()
 74 {
 75   int T,n,m,i,u,v,odd,even;
 76   scanf("%d",&T);
 77   while (T--)
 78   {
 79     scanf("%d%d",&n,&m);
 80     Now=0;
 81     memset(Head,0,sizeof(Head));
 82     for (i=1;i<=m;i++)
 83     {
 84       scanf("%d%d",&u,&v);
 85       Add(u,v); Add(v,u);
 86     }
 87     memset(parent,0,sizeof(parent));
 88     memset(vis,0,sizeof(vis));
 89     for (i=1;i<=n;i++)
 90       if (!vis[i]) dfs1(i,0,1);
 91     double_build(n);
 92     memset(vis,0,sizeof(vis));
 93     odd=even=0;
 94     for (i=1;i<=n;i++)
 95       if (!vis[i])
 96       {
 97         ans1=ans2=0;
 98         dfs2(i,0);
 99         odd=max(odd,ans1);
100         even=max(even,ans2);
101         if (odd&&even) break;
102       }
103     if (odd) printf("YES\n");
104     else printf("NO\n");
105     if (even) printf("YES\n");
106     else printf("NO\n");
107   }
108   return 0;
109 }
View Code

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5215

 

--------------------------华丽分割---------------------

蛤蛤这方法是错的==

我就是来卖个萌明天两门祝不全挂

posted on 2015-05-03 16:39  xiao_xin  阅读(812)  评论(0编辑  收藏  举报

导航