混合图(dizzy.pas/cpp/c)
混合图(dizzy.pas/cpp/c)
【题目描述】
Hzwer神犇最近又征服了一个国家,然后接下来却也遇见了一个难题。
Hzwer的国家有n个点,m条边,而作为国王,他十分喜欢游览自己的国家。他一般会从任意一个点出发,随便找边走,沿途欣赏路上的美景。但是我们的Hzwer是一个奇怪的人,他不喜欢走到自己以前走过的地方,他的国家本来有p1条有向边,p2条无向边,由于国王奇怪的爱好,他觉得整改所有无向边,使得他们变成有向边,要求整改完以后保证他的国家不可能出现从某个地点出发顺着路走一圈又回来的情况。(注:m=p1+p2.)
概述:给你一张混合图,要求你为无向图定向,使得图上没有环。
【输入格式】 dizzy.in
第一行3个整数 n,p1,p2,分别表示点数,有向边的数量,无向边的数量。
第二行起输入p1行,每行2个整数 a,b 表示a到b有一条有向边。
接下来输入p2行,每行2个整数 a,b 表示a和b中间有一条无向边。
【输出格式】 dizzy.out
对于每条无向边,我们要求按输入顺序输出你定向的结果,也就是如果你输出a b,那表示你将a和b中间的无向边定向为a->b。
注意,也许存在很多可行的解。你只要输出其中任意一个就好。
【样例输入】
4 2 3
1 2
4 3
1 3
4 2
3 2
【样例输出】
1 3
4 2
2 3
数据范围
对于20%的数据 n<=10 p1<=10 p2<=5
对于30%的数据 n<=10 p1<=30 p2<=20
对于100%的数据 n<=100000 p1<=100000 p2<=100000
数据保证至少有一种可行解。
思路:只看有向边的话,原图是个有向无环图,也就是说是个拓扑图,如果加完边后依然是拓扑图,也就是依然无环。
对原图做拓扑排序,得到每个点的入队时间,加边的时候把边定向为从入队时间早的点到晚的点,原来的入队顺序就依然成立,就无环了。
复杂度 O(p1+p2)
不知道对没对的代码(因为校验器出错了~~~~(>_<)~~~~,放一下数据和校验器,有想测的就自己测试一下,放到文件里了)。
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 100010 using namespace std; queue<int>que; int n,p1,p2,tot,num; int into[MAXN],vis[MAXN]; int to[MAXN],net[MAXN],head[MAXN]; void add(int u,int v){ to[++tot]=v;net[tot]=head[u];head[u]=tot; } int main(){ //freopen("dizzy.in","r",stdin); //freopen("dizzy.out","w",stdout); scanf("%d%d%d",&n,&p1,&p2); for(int i=1;i<=p1;i++){ int a,b; scanf("%d%d",&a,&b); add(a,b);into[b]++; } for(int i=1;i<=n;i++) if(!into[i]){ vis[i]=++num;que.push(i); } while(!que.empty()){ int now=que.front(); que.pop(); for(int i=head[now];i;i=net[i]){ into[to[i]]--; if(!into[to[i]]){ vis[to[i]]=++num; que.push(to[i]); } } } for(int i=1;i<=n;i++) cout<<vis[i]<<" ";cout<<endl; for(int i=1;i<=p2;i++){ int a,b;scanf("%d%d",&a,&b); if(vis[a]<vis[b]) printf("%d %d\n",a,b); else if(vis[a]>vis[b]) printf("%d %d\n",b,a); } return 0; } /* 4 2 3 1 2 4 3 1 3 4 2 3 2 */