标签:blog class code tar get int
仙人掌图(有向):同时满足:1强连通;2任何边不在俩个环中。
个人理解:其实就是环之间相连,两两只有一个公共点,(其实可以缩块),那个公共点是割点。HDU数据弱,网上很多错误代码和解法也可以过。
个人解法:
我认为:
:仙人掌图必然是欧拉图!这样只用“入度=出度”就可以简单地判断强连通(欧拉图显然强连通)了!而且这个必要(不充分)条件还秒杀好多数据(强连通++)。
个人证明:反证法:若有点的入度!=出度,(不妨设入度多),那么,对于每个出度,唯一从对应入度处“回来”,形成以个环,一出一入,一一对应,现在入度多的,只有从之前的出度中“回来”(鸽巢原理),这样该边在俩个环中了,矛盾。即证。
这样只是一个必要条件罢了,还有入度==出度的,但是明显存在很多环的情况,下面用以一种普遍的解法排除即可:用dfs一遍,当发现环时(dfs发现祖先点),标记该环上所有点(祖先点/割点除外),一次,若有一个点标记俩次以上(说明有边同时在俩个环),那么必然是非仙人掌了。
这俩个条件加起来,足以判断仙人掌图。虽然暂时无法证明其充分性,但也举不出反例。
可以在uva10510 提交,数据强一些。
转载请注明出处:http://write.blog.csdn.net/postedit?ref=toolbar
代码:
#include<iostream> #include<vector> #include<cstdio> #include<algorithm> using namespace std; int n; vector<vector<int> >e(100000); int ind[20010]; int outd[20010]; bool judge1() //欧拉图判断 { for(int i=0;i<n;i++) { if(ind[i]!=outd[i]) return 0; } return 1; } int vis[20010]; int fa[20010]; int mark[20010]; int flag=0; void set(int u,int vv) { mark[u]++; while(u!=vv) { u=fa[u]; mark[u]++; if(mark[u]>1&&u!=vv){flag=1;return ;} if(u==0)break; } mark[vv]--; } void dfs(int u) { if(flag)return ; for(int j=0;j<e[u].size();j++) { int vv=e[u][j]; if(!vis[vv]) { fa[vv]=u; vis[vv]=1; dfs(vv); } else set(u,vv); } return ; } bool judge2() //判定2 { vis[0]=1; dfs(0); if(flag)return 0; for(int i=0;i<n;i++) { if(mark[i]>1) return 0; } return 1; } int main() { int t; cin>>t; while(t--) { cin>>n; for(int i=0;i<=n;i++) { fa[i]=-1; mark[i]=vis[i]=ind[i]=outd[i]=0; e[i].clear(); } flag=0; int ta,tb; scanf("%d%d",&ta,&tb); while(ta!=0||tb!=0) { e[ta].push_back(tb); outd[ta]++; ind[tb]++; scanf("%d%d",&ta,&tb); } if(!judge1()) { printf("NO\n"); continue; } else { if(!judge2()) printf("NO\n"); else printf("YES\n"); } } return 0; }
hdu 3594 Cactus /uva 10510 仙人掌图判定,布布扣,bubuko.com
hdu 3594 Cactus /uva 10510 仙人掌图判定
标签:blog class code tar get int
原文地址:http://blog.csdn.net/u011498819/article/details/24921837