Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 你要把其中一些road变成单向边使得:每个town都有且只有一个入度
Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 你要把其中一些road变成单向边使得:每个town都有且只有一个入度
第一行输入n m.1 <= n<= 100000,1 <= m <= 200000 下面M行用于描述M条边.
TAK或者NIE 常做POI的同学,应该知道这两个单词的了...
并查集~
在x个点组成的联通块中,有x-1条边可以使任意x-1个点满足题意;有>=x条边可以使全部的x个点满足题意。
(一开始直接写了个dfs,一直RE,是因为爆栈吗???)
原来正解是并查集。
如果新加入的边中两个点不在同一个并查集中,那么把他们合并;
如果已经在一个并查集中了,现在又多加入一条边,那么树上必定有环,一定>=x条边了,可以使这个联通块所有点满足题意。
最后只要从1-n扫一次即可。
(注释掉的是RE的dfs)
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cmath> #define M 100000+5 using namespace std; int v[M],po,ok[M],f[M],ed,m,h[M],ans,n,tot; struct edge { int y,ne; }e[M*4]; int Getfather(int x) { return f[x]==x?x:f[x]=Getfather(f[x]); } void read(int &tmp) { tmp=0; char ch=getchar(); int fu=1; for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') fu=-1; for (;ch>='0'&&ch<='9';ch=getchar()) tmp=tmp*10+ch-'0'; tmp*=fu; } void Addedge(int x,int y) { e[++tot].y=y; e[tot].ne=h[x]; h[x]=tot; } void dfs(int x) { v[x]=1; po++; for (int i=h[x];i;i=e[i].ne) { ed++; int y=e[i].y; if (v[y]) continue; dfs(y); } } int main() { read(n),read(m); for (int i=1;i<=n;i++) f[i]=i; for (int i=1;i<=m;i++) { int x,y; read(x),read(y); //Addedge(x,y),Addedge(y,x); int fx=Getfather(x),fy=Getfather(y); if (fx==fy) ok[fx]=1; else f[fx]=fy,ok[fy]|=ok[fx]; } for (int i=1;i<=n;i++) if (!ok[Getfather(i)]) { puts("NIE"); return 0; } puts("TAK"); /* int ans=0; for (int i=1;i<=n;i++) { po=0,ed=0; if (v[i]) continue; dfs(i); ed/=2; if (ed>=po) ans+=po; else break; } if (ans==n) printf("TAK\n"); else printf("NIE\n");*/ return 0; }
感悟:
这道题让我对一棵树的概念有了进一步理解:所有点在同一个并查集中