无意中水过了这道题 就必须得对这道题负起责任。
不能随随便便A题 更不能随随便便水题 。经过思考的题目才会觉得有价值。
有向图和无向图 的混杂 我觉得很不好写 。也跟不知道怎么去写。
仔细分析我们可以得到一个结论 没有自环且有向边不存在环 把无向边 变成有向边并使图中不存在环。
这个 貌似不太好写 因为关于答案的输出必须按照输入的顺序来,那么这个问题一定是有解的了。
证明:把给定的无向边加入图中不存在环,我们可以考虑一条一条无向边按照初始的顺序变成有向边加入图中,当图中存在环,也就是不合法时不过是新图中出现了环,且刚加上的这条边使图出现了环(和我接下来学的基环树契合)那么此时我们改变环的方向环一定会消失,什么时候一定会无解呢那就是加了一条边无论哪个方向一定会都会产生一个环 此时注意 不可能有这种情况的发生,因为此时我们把它看成一条无向边的话两个环就相交了 舍弃掉这条边发现两环相交还是一个大环,那么这个大环一定会被我们之前解决掉所以说是不可能存在无解的情况的,证毕。(题目很严谨,没说无解的情况那一定有解)
此时 就出现了一个n^2的做法 我们对无向边一个一个加每加一次tarjan求强联通分量或者拓扑找环检查是否有环的存在,如果有就更换这条边的方向,然后直接输出这条边大的方向即可。可惜了 n是100000.
我不是王者,也不会n^2过百万。。。
此时讨论中有人 写了一个这样的写法所有边都加进去 然后tarjan不断找环在环上找无向边进行修改 然后最后输出即可。这个显然复杂度比较低,但是真要是卡的话我想也差不多近乎是n^2的 况且很难写 。。。想想细节就比较恶心。
我已经尽力了 和别人讨论一波发现作用不大认为关键还是在判环这个环节 能否O(1)判环,最终显然不可能。
点开题解 然后恍然 题目很好 是我太菜! 我们只在乎 不存在环即可,
那么此时我们按照拓扑排序的方式,仔细思考在什么时候回产生环 一个点连到之前的点此时成环,那么这样子只要我们直接将每个点把能跑的边全部都跑了。
那么最后一定不可能形成环,此时我们加一个d数组 表示优先级,貌似不太行,对于一些无向边他们是无出度的,我可以成对变换,但是输出时是无法判断无向边的优先级的有d数组但是发现d数组的局限性非常的大,貌似根本没什么用。
而此时对于一些无向边且入度为0 我们入度只对单向边产生影响,那么这些边的顺序就随意的了,因为不管怎么样都是只要每个点把自己发出的边全部便利完就肯定没有换的出现,而那么有入度的点就一定得按照顺序来了,不能乱整 按照拓扑序来 就可以了,我们只需拓扑序在后面的点不会再便利到前面的点即可。
然后这道题O(n)即可解决。
//#include<bits/stdc++.h> #include<iostream> #include<iomanip> #include<cmath> #include<ctime> #include<cstdio> #include<cstdlib> #include<queue> #include<stack> #include<deque> #include<vector> #include<cctype> #include<utility> #include<string> #include<cstring> #include<algorithm> #include<map> #include<set> #include<bitset> #define INF 2147483646 #define ll long long #define U unsigned #define R register #define x(i) t[i].x #define y(i) t[i].y using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return ( fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft)?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getc();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getc();} return x*f; } inline void put(int x) { x<0?x=-x,putchar(‘-‘):0; int num=0;char ch[90]; while(x)ch[++num]=x%10+‘0‘,x/=10; num==0?putchar(‘0‘):0; while(num)putchar(ch[num--]); putchar(‘ ‘);return; } const int MAXN=100002; int n,m,k; int lin[MAXN<<2],nex[MAXN<<2],ver[MAXN<<2],e[MAXN<<2],te[MAXN<<2],len; int vis[MAXN],ru[MAXN],q[MAXN<<1],T,h; void add(int x,int y,int z) { ver[++len]=y; te[len]=x; nex[len]=lin[x]; lin[x]=len; e[len]=z; } void bfs() { while(h++<T) { int te=q[h];vis[te]=1; for(int i=lin[te];i;i=nex[i]) { int tn=ver[i]; if(e[i]==1)e[i^1]=2; else if(e[i]==0){--ru[tn];if(ru[tn]==0)q[++T]=tn;} } } } int main() { //freopen("1.in","r",stdin); n=read();m=read();k=read(); for(int i=1;i<=m;++i) { int x,y; x=read();y=read(); add(x,y,0);ru[y]++; } if((len&1)==0)++len; for(int i=1;i<=k;++i) { int x,y; x=read();y=read(); add(x,y,1);add(y,x,1); } for(int i=1;i<=n;++i)if(ru[i]==0)q[++T]=i; bfs(); //for(int i=1;i<=n;++i)put(dis[i]); for(int i=1;i<=len;++i)if(e[i]==1)printf("%d %d\n",te[i],ver[i]); return 0; }
哎。太菜了。
至于bzoj这道题 其实我们只要特判样例即可水过只有一个测试点有数据 好坑。。。
原文地址:https://www.cnblogs.com/chdy/p/10590296.html