AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1116
[分析]
题目中要求“你要把其中一些road变成单向边使得:每个town都有且只有一个入度”。
那么,什么时候能满足这个条件呢?
我们思考一下:在一个连通分量中,当其中有环的时候,我们可以通过删边(不将它变为有向边)使这个环上的点都有且只有一个入度。因为它们构成了环,所以必然还有出边。在连通分量中,每一个点都可以间接或直接地被这些出边所连接,及它们一定会有入度,而我们也可以通过删边将它们变为有且只有一个入度的点。
综上,在一个连通分量中,只要有环,则其中的所有点都可以通过“把其中一些road变成单向边”变为有且只有一个入度的点。
所以算法就很显然了:逐个考虑连通分量,判断是否存在环。若每个连通分量中都存在环,则图就满足条件。至于如何判环,就看各位的爱好了。
#include <iostream>
#include <cstdio>
using namespace std;
int n,m;
int inp[200010][3];
int fa[200010];
int mem[100010];
bool is_circle[100010];
int find(int x){
int tmp=x,pre;
while(tmp!=fa[tmp])tmp=fa[tmp];
while(x!=tmp){
pre=fa[x];
fa[x]=tmp;
x=pre;
}
return tmp;
}
void merge(int x,int y){
int fx=find(x),fy=find(y);
fa[fx]=fy;
}
void merge2(int x,int y){
int fx=find(x),fy=find(y);
if(fx==fy)is_circle[mem[fx]]=true;
else fa[fx]=fy;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
inp[i][1]=x;
inp[i][2]=y;
merge(x,y);
}
for(int i=1;i<=n;i++){int fi=find(i);mem[i]=fi;}
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++)merge2(inp[i][1],inp[i][2]);
for(int i=1;i<=n;i++)
if(!is_circle[mem[i]]){printf("NIE");return 0;}
printf("TAK");
return 0;
}