2010-1127

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

这题的题意可以简化为,在一个图内,某两个点的所有路径的公共边。

首先对图进行dfs,找到其中的关键边(桥),在遍历得到的树中找到这两个点的路径,则这条路径中所包含的桥就是答案.需要注意的就是平行边的处理。


{{{
#!cpp
#include <cstdio>
#include <utility>
#include <cstring>
#include <vector>
using namespace std;


typedef pair<int,int> pii;

const int maxn=10100;
const int maxm=200100;
int prev[maxn];
int luangao[maxn];
int cnt;
int low[maxn];
int v[maxn];
vector<pii> e[maxn];

int gao(int f, int u , int t,int cnt){
    prev[u] = f; 
    luangao[u] = cnt;
    low[u] =luangao[u];
    v[u] =1;
    for(int i=0;i<e[u].size();++i)if(i!=t){
        int uu = e[u][i].first ;
//      if ( uu == f ) continue;
    //  if ( uu == u ) continue;
        if ( v[uu] == 1 ) {

            if ( luangao[uu] < low[u] ) low[u] =luangao[uu];

        }
        else if ( !v[uu] )  {

            gao(u,uu,e[u][i].second,cnt+1);
            if ( low[uu] < low[u] ) low[u] = low[uu];

        }
    }
    v[u]=2;
    return 0;
}
int n;

int gao2(int f, int u){
    if ( v[u] ) return 0 ;
    prev[u] = f; 
    v[u]=1;
    if ( u == n-1 ) return 1;
    for(int i=0;i<e[u].size();++i){
        if ( gao2(u,e[u][i].first) ) 
            return 1;
    }
    return 0;
}

int a[maxm],b[maxm];
int ok[maxm];
int main(){

    int m;
    while ( scanf("%d%d",&n,&m)!=EOF ) {
        for(int i=0;i<maxn;++i)e[i].clear();

        memset(ok,0,sizeof(ok));
        cnt=0;
        for(int i=0;i<m;++i){
            scanf("%d%d",a+i,b+i);
            e[a[i]].push_back(make_pair(b[i],e[b[i]].size()));
            e[b[i]].push_back(make_pair(a[i],e[a[i]].size()-1));
        }
        memset(prev,-1,sizeof(prev));
        memset(v,0,sizeof(v));
        memset(low,10,sizeof(low));
        memset(luangao,0,sizeof(luangao));
        gao(-1,0,-1,0);

        for(int i=0;i<m;++i){

            int u = a[i] , uu =b[i];
            if ( !v[u] || !v[uu] ) continue;
            if ( prev[u] == uu && luangao[uu] < low[u] || prev[uu] == u && luangao[u] < low[uu] ){
                ok[i] =1;
            }

        }

        int l[maxn];
        int tt =0;
/*memset(v,0,sizeof(v));
        memset(prev,-1,sizeof(prev));
        gao2(-1,0);*/
        for(int i=n-1;i!=-1;i=prev[i]){
            l[tt++]= i;
        }
        memset(prev,-1,sizeof(prev));
        for(int i=0;i<tt-1;++i){
            prev[l[i]] = l[i+1];
        }


        vector<int> ans;

        for(int i=0;i<m;++i)if ( ok[i] ) {
            if ( prev[a[i]] == b[i] || prev[b[i]] == a[i] ) 
                ans.push_back(i);
        }

        printf("%d\n" ,ans.size());
        for(int i =0;i<ans.size();++i){
            if ( i ) printf(" ");
            printf("%d", ans[i]);
        }
        printf("\n");


    }

    return 0;
}


}}}

这题的题意可以简化为,在一个图内,某两个点的所有路径的公共边。

首先对图进行dfs,找到其中的关键边(桥),在遍历得到的树中找到这两个点的路径,则这条路径中所包含的桥就是答案.需要注意的就是平行边的处理。

#include <cstdio>
#include <utility>
#include <cstring>
#include <vector>
using namespace std;
typedef pair<int,int> pii;
const int maxn=10100;
const int maxm=200100;
int prev[maxn];
int luangao[maxn];
int cnt;
int low[maxn];
int v[maxn];
vector<pii> e[maxn];
int gao(int f, int u , int t,int cnt){
    prev[u] = f; 
    luangao[u] = cnt;
    low[u] =luangao[u];
    v[u] =1;
    for(int i=0;i<e[u].size();++i)if(i!=t){
        int uu = e[u][i].first ;
//      if ( uu == f ) continue;
    //  if ( uu == u ) continue;
        if ( v[uu] == 1 ) {
            if ( luangao[uu] < low[u] ) low[u] =luangao[uu];
        }
        else if ( !v[uu] )  {
            gao(u,uu,e[u][i].second,cnt+1);
            if ( low[uu] < low[u] ) low[u] = low[uu];
        }
    }
    v[u]=2;
    return 0;
}
int n;
int gao2(int f, int u){
    if ( v[u] ) return 0 ;
    prev[u] = f; 
    v[u]=1;
    if ( u == n-1 ) return 1;
    for(int i=0;i<e[u].size();++i){
        if ( gao2(u,e[u][i].first) ) 
            return 1;
    }
    return 0;
}
int a[maxm],b[maxm];
int ok[maxm];
int main(){
    int m;
    while ( scanf("%d%d",&n,&m)!=EOF ) {
        for(int i=0;i<maxn;++i)e[i].clear();
        memset(ok,0,sizeof(ok));
        cnt=0;
        for(int i=0;i<m;++i){
            scanf("%d%d",a+i,b+i);
            e[a[i]].push_back(make_pair(b[i],e[b[i]].size()));
            e[b[i]].push_back(make_pair(a[i],e[a[i]].size()-1));
        }
        memset(prev,-1,sizeof(prev));
        memset(v,0,sizeof(v));
        memset(low,10,sizeof(low));
        memset(luangao,0,sizeof(luangao));
        gao(-1,0,-1,0);
        for(int i=0;i<m;++i){
            int u = a[i] , uu =b[i];
            if ( !v[u] || !v[uu] ) continue;
            if ( prev[u] == uu && luangao[uu] < low[u] || prev[uu] == u && luangao[u] < low[uu] ){
                ok[i] =1;
            }
        }
        int l[maxn];
        int tt =0;
/*memset(v,0,sizeof(v));
        memset(prev,-1,sizeof(prev));
        gao2(-1,0);*/
        for(int i=n-1;i!=-1;i=prev[i]){
            l[tt++]= i;
        }
        memset(prev,-1,sizeof(prev));
        for(int i=0;i<tt-1;++i){
            prev[l[i]] = l[i+1];
        }
        vector<int> ans;
        for(int i=0;i<m;++i)if ( ok[i] ) {
            if ( prev[a[i]] == b[i] || prev[b[i]] == a[i] ) 
                ans.push_back(i);
        }
        printf("%d\n" ,ans.size());
        for(int i =0;i<ans.size();++i){
            if ( i ) printf(" ");
            printf("%d", ans[i]);
        }
        printf("\n");
    }
    return 0;
}