CLO [POI/BZOJ 1116]

来源:互联网 发布:翁恺java语言百度网盘 编辑:程序博客网 时间:2024/05/29 06:44

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;}



1 0
原创粉丝点击