POJ1515Street Direction(无向图改有向图)
题意:
把尽可能多的无向边改成有向边,使得图依然为强连通图
思路:
首先桥必是无向边,不能变。桥左右连接的是强连通分量,对每个强连通分量跑dfs,确定每条边的放方向
#include<iostream>
#include<cstring>
#define N 100001
#define LL long long
using namespace std;
struct Edge{
int from,to,next;
int cut;//记录该边是否为桥
Edge(){}
Edge(int from,int to,int next,int cut):from(from),to(to),next(next),cut(cut){}
}edge[N*2];//双向边edge[i]与edge[i^2]是两条反向边
int n,m;
int head[N],edgeNum;
int dfn[N],low[N],block_cnt;
bool vis[N];//dfs确定边的方向时的标志数组
bool sig;//判断是否连通
void addEdge(int from,int to){//添边
edge[edgeNum]=Edge(from,to,head[from],false);
head[from]=edgeNum++;
}
void tarjin(int x,int father){
low[x]=dfn[x]=++block_cnt;
for(int i=head[x];i!=-1;i=edge[i].next) {
int y=edge[i].to;
if(y==father)continue;
if(!dfn[y]){
tarjin(y,x);
if(low[x]>low[y])
low[x]=low[y];
if(low[y]>dfn[x])
edge[i].cut=edge[i^1].cut=true;
}
else if(low[x]>dfn[y])
low[x]=dfn[y];
}
}
void dfs(int x, int father){
vis[x]=true;
for(int i=head[x];~i;i=edge[i].next){
int y=edge[i].to;
if(edge[i].cut==1)
continue;
if(edge[i^1].cut!=-1)
edge[i].cut=-1;
if(!vis[y])
dfs(y,x);
}
}
int main()
{
int r=0;
while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){
memset(dfn,0,sizeof(dfn));
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
edgeNum=0;
while(m--){
int x,y;
scanf("%d%d",&x,&y);
addEdge(x,y);
addEdge(y,x);
}
tarjin(1,1);
for(int i=1;i<=n;i++)
if(!vis[i])
dfs(i,i);
printf("%d\n\n",++r);
for(int i=0;i<edgeNum;i++)
if(edge[i].cut)
printf("%d %d\n",edge[i].from,edge[i].to);
printf("#\n");
}
return 0;
}