ZOJ 2588 Burning Bridges 求无向图桥 边双连通裸题

来源:互联网 发布:信用卡垫还 app 源码 编辑:程序博客网 时间:2024/06/05 16:46

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1588

binshen的板子:

#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;const int INF = 0x3f3f3f3f;/**  求 无向图的割点和桥*  可以找出割点和桥,求删掉每个点后增加的连通块。*  需要注意重边的处理,可以先用矩阵存,再转邻接表,或者进行判重*/const int MAXN = 10010;const int MAXM = 2000010;struct Edge{    int to,next;    int w;    bool cut;//是否为桥的标记}edge[MAXM];int head[MAXN],tot;int Low[MAXN],DFN[MAXN],Stack[MAXN];int Index,top;bool Instack[MAXN];bool cut[MAXN];int add_block[MAXN];//删除一个点后增加的连通块int bridge;void addedge(int u,int v,int w){    edge[tot].to = v;edge[tot].next = head[u];edge[tot].cut = false;    edge[tot].w = w;    head[u] = tot++;    edge[tot].to = u;edge[tot].next = head[v];edge[tot].cut = false;    edge[tot].w = w;    head[v] = tot++;}void Tarjan(int u,int pre){    int v;    Low[u] = DFN[u] = ++Index;    Stack[top++] = u;    Instack[u] = true;    int son = 0;    int pre_num = 0;    for(int i = head[u];i != -1;i = edge[i].next)    {        v = edge[i].to;        if(v == pre && pre_num == 0){pre_num++;continue;}        if( !DFN[v] )        {            son++;            Tarjan(v,u);            if(Low[u] > Low[v])Low[u] = Low[v];            //桥            //一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u)<Low(v)。            if(Low[v] > DFN[u])            {                bridge++;                edge[i].cut = true;                edge[i^1].cut = true;            }            //割点            //一个顶点u是割点,当且仅当满足(1)或(2) (1) u为树根,且u有多于一个子树。            //(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,            //即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)            if(u != pre && Low[v] >= DFN[u])//不是树根            {                cut[u] = true;                add_block[u]++;            }        }        else if( Low[u] > DFN[v])             Low[u] = DFN[v];    }    //树根,分支数大于1    if(u == pre && son > 1)cut[u] = true;    if(u == pre)add_block[u] = son - 1;    Instack[u] = false;    top--;}void solve(int N){    memset(DFN,0,sizeof(DFN));    memset(Instack,false,sizeof(Instack));    memset(add_block,0,sizeof(add_block));    memset(cut,false,sizeof(cut));    Index = top = 0;    bridge = 0;    for(int i = 1;i <= N;i++)if(!DFN[i])Tarjan(i,i);}void init(){ tot = 0;  memset(head,-1,sizeof(head));}vector<int>G;  int n, m;int main(){      int u, v, i, j, T; scanf("%d",&T);      while(T--){          scanf("%d %d",&n,&m);          init();          while(m--){              scanf("%d %d",&u,&v);              addedge(u,v,1);          }          solve(n);          G.clear();          for(i=0;i<tot;i+=2)if(edge[i].cut)G.push_back(i/2);          printf("%d\n",G.size());          for(i=0;i<G.size();i++){              printf("%d",G[i]+1);              i==G.size()-1?puts(""):printf(" ");          }          if(T)puts("");      }      return 0;  } 


#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#include<vector>using namespace std;#define N 10050#define M 200005int n,m;//n个点 m条边struct Edge{int from,to,val,nex;bool cut;//记录这条边是否为割边 }edge[2*M];//双向边则 edge[i]与edge[i^1]是2条反向边int head[N],edgenum;//在一开始就要 memset(head,-1,sizeof(head)); edgenum=0;int low[N],dfn[N],tarjin_time;void add(int u,int v,int w){Edge E={u,v,w,head[u],0};edge[edgenum]=E;head[u]=edgenum++;Edge E2={v,u,w,head[v],0};edge[edgenum]=E2;head[v]=edgenum++;}void tarjin(int u,int pre){low[u]=dfn[u]= ++tarjin_time;int flag=1;//flag是阻止双向边的反向边 i和i^1for(int i=head[u];i!=-1;i=edge[i].nex){int v=edge[i].to;if(flag&&v==pre){flag=0;continue;}if(!dfn[v]){tarjin(v,u);if(low[u]>low[v])low[u]=low[v];if(low[v]>dfn[u])//是桥low[v]表示v能走到的最早祖先 有重边且u是v的最早祖先 则low[v]==dfn[u],所以不会当作桥edge[i].cut=edge[i^1].cut=true;}else if(low[u]>dfn[v])low[u]=dfn[v];}}void find_edgecut(){memset(dfn,0,sizeof(dfn));tarjin_time=0;for(int i=1;i<=n;i++)if(!dfn[i])tarjin(i,i);}void init(){memset(head, -1, sizeof head); edgenum = 0;}vector<int>G;int main(){int u, v, i, j, T; scanf("%d",&T);while(T--){scanf("%d %d",&n,&m);init();while(m--){scanf("%d %d",&u,&v);add(u,v,1);}find_edgecut();G.clear();for(i=0;i<edgenum;i+=2)if(edge[i].cut)G.push_back(i/2);printf("%d\n",G.size());for(i=0;i<G.size();i++){printf("%d",G[i]+1);i==G.size()-1?puts(""):printf(" ");}if(T)puts("");}return 0;}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 pdf格式不能打印怎么办 pdf文件没有打印怎么办 打印机添加不上怎么办 笔记本电脑收不到wifi怎么办 账套输出不了怎么办 无法加载pdf文档怎么办 pdf控件不可用怎么办 扫描件不清晰怎么办 图片大于200k怎么办 手机图片字模糊怎么办 天然气手册丢了怎么办 消消乐登录异常怎么办 新手想学考古怎么办 省份证改名字怎么办 文曲星放太久开不了机怎么办 小狗吃火腿肠皮怎么办 虚火引起的牙痛怎么办 牙髓炎怎么办立刻止疼 小蜜丸吃不下去怎么办 铜钱的字不认识怎么办 古钱币出手好烦怎么办 安装目录不可写怎么办 手机不支持exfat格式怎么办 windows7图标变大了怎么办 igs格式烂曲面怎么办 手机桌面文件夹打不开怎么办 苹果下载不了150怎么办 iphone6速度变慢怎么办 苹果手机微信打不开pdf怎么办 苹果手机打不开pdf怎么办 pdf文件超过了怎么办 pdf电脑删不了怎么办 联想笔记本摄像头横屏调竖屏怎么办 pdf文件打开失败怎么办 pdf复制文字乱码怎么办 电子发票乱码了怎么办 超星尔雅挂了怎么办 电脑应用双击打不开怎么办 电脑控制面板打不开怎么办 转换器无法打开文件怎么办 电脑文件无法打开怎么办