UVA 610



  Street Directions 

According to the Automobile Collision Monitor (ACM), most fatal traffic accidents occur on two-way streets. In order to reduce the number of fatalities caused by traffic accidents, the mayor wants to convert as many streets as possible into one-way streets. You have been hired to perform this conversion, so that from each intersection, it is possible for a motorist to drive to all the other intersections following some route.


You will be given a list of streets (all two-way) of the city. Each street connects two intersections, and does not go through an intersection. At most four streets meet at each intersection, and there is at most one street connecting any pair of intersections. It is possible for an intersection to be the end point of only one street. You may assume that it is possible for a motorist to drive from each destination to any other destination when every street is a two-way street.

Input 

The input consists of a number of cases. The first line of each case contains two integers  n  and  m . The number of intersections is  n  (  $2 \leŸ n \leŸ 1000$ ), and the number of streets is  m . The next  m  lines contain the intersections incident to each of the  m  streets. The intersections are numbered from 1 to  n , and each street is listed once. If the pair  $i\ j$  is present,  $j\ i$  will not be present. End of input is indicated by  n  =  m  = 0.

Output 

For each case, print the case number (starting from 1) followed by a blank line. Next, print on separate lines each street as the pair  $i\ j$  to indicate that the street has been assigned the direction going from intersection  i  to intersection  j . For a street that cannot be converted into a one-way street, print both  $i\ j$  and  $j\ i$  on two different lines. The list of streets can be printed in any order. Terminate each case with a line containing a single ` # ' character.


Note: There may be many possible direction assignments satisfying the requirements. Any such assignment is acceptable.

Sample Input 

7 10
1 2
1 3
2 4
3 4
4 5
4 6
5 7
6 7
2 5
3 6
7 9
1 2
1 3
1 4
2 4
3 4
4 5
5 6
5 7
7 6
0 0

Sample Output 

1

1 2
2 4
3 1
3 6
4 3
5 2
5 4
6 4
6 7
7 5
#
2

1 2
2 4
3 1
4 1
4 3
4 5
5 4
5 6
6 7
7 5
#



Miguel A. Revilla 
1999-03-24


一个国家有很多的双向路,现在我们想把尽可能多的路变成单向路,使得对于任意的i,j两个城市都存在从i到j的路径。

抽象的的来说,现在给你一个连通的无向图,现在要把尽可能多的路定向,对于不能定向的路{i,j},拆成两条有向边<i,j>,使得我们得到的有向图是强连通的。


定理:若无向图G是连通图,且图G中不存在桥,则图G存在强连通的定向图。


证明:图G中不存在桥,在G中必然存在一个圈C1。我们定义图G的一个连通子图序列G1,G2,……Gn。

  1、令G1=C1,显然子图G1存在强连通的定向图。

  2、若|V(Gi)|=V|G|则命题得证,否则必然存在一点Vi不属于Gi,由于G中不存在桥,则存在至少两条从Gi到Vi的路Pi,Qi。我们定义Gi+1=Gi+Pi+Qi+Vi。由于|V(Gi+1)|=|V(Gi)|+1。所以必然有i满足|V(Gi)|=V|G|。


那么切掉所有的桥之后,图转化为多个连通块,每个连通块不存在桥,那么从连通块任意一点开始dfs,设一次的dfs序列是v1 v2 v3 ....vn那么必然存在一条边{vn,v1}虽然v1这一点我们不会再次访问,但是{vn,v1}这条边我们是一定会访问到的,把这条边定向为<vn,v1>即可。所以我们只需要按dfs自动生成的顺序去定向边就可以了。


#include<cstdio>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<algorithm>
#include<map>
#include<iostream>
#include<string>
#define maxn 1009
#define maxm 200009
using namespace std;
int first[maxn];
int dfn[maxn],low[maxn],vis[maxn];
int next[maxm],u[maxm],v[maxm],ed[maxm];
bool flag[maxm];
int n,m,tot,dfs_time;
void add(int x,int y)
{
    u[tot]=x;v[tot]=y;
    next[tot]=first[x];
    first[x]=tot++;
}
void dfs(int cur,int fa)
{
    vis[cur]=1;
    low[cur]=dfn[cur]=++dfs_time;
    for(int i=first[cur];i!=-1;i=next[i])
    {
        if(v[i]!=fa&&vis[v[i]]==1)
            low[cur]=min(low[cur],dfn[v[i]]);
        if(vis[v[i]]==0)
        {
            dfs(v[i],cur);
            low[cur]=min(low[cur],low[v[i]]);
            if(low[v[i]]>dfn[cur])
                flag[i]=flag[i^1]=1;
        }
    }
}
void path(int cur)
{
    vis[cur]=1;
    for(int i=first[cur];i!=-1;i=next[i])
    {
        if(!flag[i])
        {
            if(!ed[i]){
            printf("%d %d\n",cur,v[i]);//按dfs自动生成的顺序定向边
            ed[i]=ed[i^1]=1;}
            if(!vis[v[i]]) 
                path(v[i]);
        }
    }
}
int main()
{
    int cot=0;
    while(scanf("%d%d",&n,&m),m||n)
    {
        memset(first,-1,sizeof(first));tot=0;
        for(int i=0;i<m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        memset(flag,0,sizeof(flag));
        memset(vis,0,sizeof(vis));
        dfs_time=0;
        dfs(1,-1);
        memset(vis,0,sizeof(vis));
         cot++;
        printf("%d\n\n",cot);
        memset(ed,0,sizeof(ed));
        for(int i=1;i<=n;i++)
            if(!vis[i])
            path(i);
       for(int i=0;i<tot;i+=2)
            if(flag[i])
            printf("%d %d\n%d %d\n",u[i],v[i],v[i],u[i]);
        printf("#\n");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值