hdu 3394 Railway【点双连通分量、桥、割点】

    xiaoxiao2021-03-25  97

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3394

    题意:

    有一个公园有n个景点,公园的管理员准备修建m条道路,并且安排一些形成回路的参观路线。如果一条道路被多条道路公用,那么这条路是冲突的;如果一条道路没在任何一个回路内,那么这条路是不冲突的

    问分别有多少条有冲突的路和没有冲突的路

    分析:

    1.“多余边”不在任何一个环中,那么多余边一定是桥,所以统计这个无向图中有多少桥即可

    2.“冲突边”有多少,这个有点费劲,但是不难想到。如果一个环比较特殊,n个点刚好n条边,例如(1,2)(2,3)(1,3)这种环,这个环内,一条“冲突边”都没有,但是如果一个环内的边数大于点数,那么这个环内所有边都是“冲突边”(真可惜,因为有多出来的那些边后,相当于把最外面的大环分割成了内部的几个小环,这些小环和小环之间,小环和大环之间一定会公用一些边,这些边就是“冲突边”,而且可以发现,所有边都会被公用,太可惜了……),例如sample里面的(5,6)(5,4)(6,7)(4,7)(5,7),相当于最外面的大环<6,5,4,7,6> , 而里面的边(5,7)把这个大环分割成了两个小环

    所以做法就是,求出这个无向图有多少个点双连通分量,对于每个点双连通分量,如果内部的边数>点数,那么这些边全部都是冲突边

    代码:

    #include<cstdio> #include<cstring> #include<queue> #include<vector> #include<algorithm> #include<stack> using namespace std; const int N=10000+10; int n,m; int ans1,ans2;//多余边,冲突边 vector<int> g[N],bcc[N]; int dfs_clock,bcc_cnt; int pre[N],low[N],bccno[N],iscut[N]; struct Edge { int u,v; Edge(int u,int v):u(u),v(v) {} }; stack<Edge> S; int vis[N]; void solve(int x) { int sum=0,len=bcc[x].size(); memset(vis,0,sizeof(vis)); for(int i=0; i<len; i++) vis[bcc[x][i]]=1; for(int i=0; i<len; i++) { int u=bcc[x][i]; for(int j=0; j<g[u].size(); j++) if(vis[g[u][j]]) sum++; } sum /=2; if(sum>len) ans2+= sum; } void tarjan(int u,int fa) { low[u]=pre[u]=++dfs_clock; int child=0; for(int i=0; i<g[u].size(); i++) { int v=g[u][i]; if(v==fa) continue; Edge e=Edge(u,v); if(!pre[v]) { S.push(e); child++; tarjan(v,u); low[u]=min(low[u],low[v]); if(low[v]>=pre[u]) { //u是割点 iscut[u]=true; if(low[v]>pre[u]) ans1++;//桥 bcc_cnt++; bcc[bcc_cnt].clear(); while(true) { Edge x=S.top(); S.pop(); if(bccno[x.u]!=bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u]=bcc_cnt; } if(bccno[x.v]!=bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v]=bcc_cnt; } if(x.u==u && x.v==v) break; } solve(bcc_cnt); } } else if(pre[v]< pre[u]) { S.push(e); low[u]=min(pre[v],low[u]); } } if(fa<0&&child==1)iscut[u]=0; } int main() { // freopen("in.txt","r",stdin); while(scanf("%d%d",&n,&m)==2&&n) { ans1=ans2=bcc_cnt=dfs_clock=0; memset(pre,0,sizeof(pre)); memset(bccno,0,sizeof(bccno)); for(int i=0; i<=n; i++) g[i].clear(); while(m--) { int u,v; scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } for(int i=0; i<n; i++) if(!pre[i]) tarjan(i,-1); printf("%d %d\n",ans1,ans2); } return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-20502.html

    最新回复(0)