<题目链接>
题目大意:
给定一个混合图,问你在能够使得图中所有点能够两两到达的情况下,尽可能多的将无向边变成有向边,输出这些无向边的变化方案。
解题分析:
这与之前做过的这道题非常类似 POJ 1515 ,不同的是,本题是混合图。总体的思路还是相同的,就是将无向边定向,但是原图中的桥一定只能是双向的,否则不可能使得所有点两两相互到达,之后就是记录一下无向边定向后的结果即可。
#include <cstdio> #include <algorithm> #include <cstring> #include <iostream> using namespace std; #define rep(i,s,t) for(int i=s;i<=t;i++) #define clr(a,b) memset(a,b,sizeof a) const int N = 2e3+5 , M = N*N; struct Edge{ int to,nxt,fp,cur; }e[M]; //fp表示这是单向边,双向边,或者在原图中不存在,cur用来给这条边定向 int n,m,cnt,tot; int head[N],low[N],dfn[N]; inline void init(){ cnt=tot=0; clr(dfn,0);clr(head,-1);clr(low,0); } inline void add(int u,int v,int flag){ e[cnt]=(Edge){v,head[u],flag,-1};head[u]=cnt++; } void Tarjan(int u,int pre){ dfn[u]=low[u]=++tot; for(int i=head[u];~i;i=e[i].nxt){ int v=e[i].to; if(v==pre)continue; if(e[i].cur!=-1)continue; //如果该边之前已经定过向 if(!e[i].fp)continue; //如果改边在原图中不存在 e[i].cur=1,e[i^1].cur=0; if(!dfn[v]){ Tarjan(v,u); low[u]=min(low[u],low[v]); if(low[v]>dfn[u])e[i].cur=e[i^1].cur=1; }else low[u]=min(low[u],dfn[v]); } } int main(){ while(cin>>n>>m){ init(); rep(i,1,m){ int u,v,c;scanf("%d%d%d",&u,&v,&c); if(c==1)add(u,v,1),add(v,u,0); else add(u,v,2),add(v,u,2); } rep(i,1,n) if(!dfn[i]){ Tarjan(i,-1); } //只输出双向边的处理方案 for(int i=0;i<cnt;i+=2){ if(e[i].fp==2&&e[i].cur==1&&e[i^1].cur==1)printf("%d %d 2 ",e[i^1].to,e[i].to); else if(e[i].fp==2&&e[i].cur==1&&e[i^1].cur==0)printf("%d %d 1 ",e[i^1].to,e[i].to); //e[i]边有效,所以是e[i^1].to--->e[i].to else if(e[i].fp==2&&e[i].cur==0&&e[i^1].cur==1)printf("%d %d 1 ",e[i].to,e[i^1].to); } } }