【传送门:BZOJ1116】
简要题意:
给出n个点,m条无向边,判断是否能够通过将某些边变成单向边,使得每个点入度都为1
题解:
因为每个点入度都为1时,必定是一棵外向树,而外向树有且仅有一个环
那么就判断所有连通图是否满足有且只有一个简单环,用tarjan来判
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[410000];int len,last[110000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } bool v[110000]; int dfn[110000],low[110000],id; int sta[110000],tp; int cnt; void tj(int x,int fa) { dfn[x]=low[x]=++id; sta[++tp]=x;v[x]=true; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y==fa) continue; if(dfn[y]==0) { tj(y,x); low[x]=min(low[x],low[y]); } else if(v[y]==true) low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]) { int i,sum=0; do { i=sta[tp--]; v[i]=false;sum++; }while(i!=x); if(sum>=3) cnt++; } } int main() {int n,m; scanf("%d%d",&n,&m); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } memset(v,false,sizeof(v)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); id=tp=cnt=0; for(int i=1;i<=n;i++) { if(dfn[i]==0) { tj(i,0); if(cnt!=1) { printf("NIE "); return 0; } cnt=0; } } printf("TAK "); return 0; }