HDU3594 Cactus 判断是否为仙人掌图 难度中

这道题目挺有意思,amb大牛还发了那个强大的仙人掌图剖析的pdf,自己yy了一种解法,由于HDU上的数据够弱,

暂时没有发现自己的代码有啥错误的。网上各种代码错误,还各种ac了~~这道题的数据,汗~~

可以测测这一组数据:

1
4
0 1
1 2
2 0
2 3
3 2
3 0
0 0

正确输出:no

/*
*State: HDU3594 78MS 2644K 3134 B C++ 
*题目大意:
*        给一个有向图,判断这个有向图是否为仙人掌图。
*        仙人掌图满足:1、是强连通图 2、每条边都只属于一个环
*解题思路:
*        判断强连通比较好做,主要是要判断每条边都属于一个环。
*        我想到了用块来判断,但是只用块判断过无向图,但是用笔模拟
*        了下,感觉有向图跟无向图都是一样的判断。
*        就保存了有向图跟无向图,想想一个强连通图是仙人掌图,那么
*        它从无向图上看一定是多个块之间靠一个点连接起来。那么好做
*        把它保存为无向图,然后求块,判断每个块中边的个数是否等于
*        块中点的个数,即可判断是否每条边只属于一个环。
*解题感想;
*        1a了,没想到这么神奇,看来专注是必须的。
*        这道题目的数据比较水,该方法还有待验证。
*        该题值得慢慢品味
*/
View Code
  1 #include <iostream>
  2 using namespace std;
  3 
  4 const int MAXN = 20005;
  5 const int MAXE = 50005;
  6 
  7 typedef struct _node
  8 {
  9     int v, next, isdir;
 10     _node() :isdir(0) {};
 11 }N;
 12 
 13 N edge[MAXE * 2];
 14 int head[MAXN], cntEdge, myS[MAXN], top;
 15 int inS[MAXN], isScc;
 16 
 17 int bMyS[MAXN], bTop;
 18 int low[MAXN], dfn[MAXN], step;
 19 
 20 int block[MAXN], isOneCir;
 21 
 22 void init()
 23 {
 24     top = bTop = 0;
 25     cntEdge = 0;
 26     isScc = false;
 27     isOneCir = true;
 28     for(int i = 0; i < MAXN; i++)
 29     {
 30         inS[i] = 0;
 31         head[i] = -1;
 32     }
 33 }
 34 
 35 void addEdge(int u, int v)
 36 {
 37     edge[cntEdge].v = v;
 38     edge[cntEdge].isdir = 1;
 39     edge[cntEdge].next = head[u];
 40     head[u] = cntEdge++;
 41 
 42     edge[cntEdge].v = u;
 43     edge[cntEdge].next = head[v];
 44     edge[cntEdge].isdir = 0;
 45     head[v] = cntEdge++;
 46 }
 47 
 48 void tarjan_scc(int n, int toln)
 49 {
 50     dfn[n] = low[n] = ++step;
 51     myS[top++] = n;
 52     inS[n] = 1;
 53     for(int f = head[n]; f != -1; f = edge[f].next)
 54     {
 55         if(!edge[f].isdir)
 56             continue;
 57         int son = edge[f].v;
 58         if(dfn[son] == -1)
 59         {
 60             tarjan_scc(son, toln);
 61             low[n] = min(low[n], low[son]);
 62         }
 63         else if(inS[son] == 1)
 64             low[n] = min(low[n], dfn[son]);
 65     }
 66     if(low[n] == dfn[n] && top != 0)
 67     {
 68         int _cnt = 0;
 69         int tmp;
 70         do
 71         {
 72             tmp = myS[--top];
 73             _cnt++;
 74         }while(top != 0 && tmp != n);
 75         if(_cnt == toln)
 76             isScc = true;
 77     }
 78 }
 79 
 80 void judge()
 81 {
 82     int vst[MAXN] = {0};
 83     for(int i = 1; i <= block[0]; i++)
 84     {
 85         vst[block[i]] = 1;
 86     }
 87     int u, v, sum = 0;
 88     for(int i = 1; i <= block[0]; i++)
 89     {
 90         u = block[i];
 91         for(int f = head[u]; f != -1; f = edge[f].next)
 92         {
 93             v = edge[f].v;
 94             if(vst[v])
 95                 sum++;
 96         }
 97     }
 98     sum /= 2;
 99     if(isOneCir == true && sum != block[0])
100         isOneCir = false;
101 }
102 
103 //求块
104 void tarjan_block(int n)
105 {
106     dfn[n] = low[n] = ++step;
107     bMyS[bTop++] = n;
108 
109     for(int f = head[n]; f != -1; f = edge[f].next)
110     {
111         int son = edge[f].v;
112         if(dfn[son] == -1)
113         {
114             tarjan_block(son);
115             low[n] = min(low[n], low[son]);
116 
117             if(low[son] >= dfn[n])
118             {
119                 block[0] = 0;
120                 int tmp;
121                 while(true)
122                 {
123                     tmp = bMyS[bTop - 1];
124                     block[++block[0]] = tmp;
125                     if(bMyS[--bTop] == son)
126                         break;
127                 }
128                 block[++block[0]] = n;
129                 judge();
130             }
131         }
132         else
133             low[n] = min(low[n], dfn[son]);
134     }
135 }
136 
137 int main(void)
138 {
139 #ifndef ONLINE_JUDGE
140     freopen("in.txt", "r", stdin);
141 #endif
142 
143     int cas;
144     scanf("%d", &cas);
145     while(cas--)
146     {
147         init();
148         int n, u, v;
149         scanf("%d", &n);
150         while(scanf("%d %d", &u, &v), u || v)
151         {
152             addEdge(u, v);
153         }
154         for(int i = 0; i < MAXN; i++)
155             dfn[i] = low[i] = -1;
156         step = 0;
157         tarjan_scc(0, n);
158 
159         //强连通才继续判断
160         for(int i = 0; i < MAXN; i++)
161             dfn[i] = low[i] = -1;
162         step = 0;
163 
164         if(isScc)
165             tarjan_block(0);
166 
167         if(isScc && isOneCir)
168             printf("YES\n");
169         else
170             printf("NO\n");
171     }
172     return 0;
173 }

转载于:https://www.cnblogs.com/cchun/archive/2012/08/16/2641080.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值