HDU 4738 Caocao's Bridges(重边无向图求桥)
来源:互联网 发布:南京江北新区网络问政 编辑:程序博客网 时间:2024/06/03 03:54
现在有个(可重边)无向图,无向图的每条边上都有一定数目的守卫,你现在想派人去炸掉这个图的一条边,是的该图不连通。但是你只能炸1条边且如果该边守卫为x人,那么你至少要派x个人过去。所以现在问你最少需要派多少人出发?
思路:就是求一个有重边的无向图的桥,有几个比较坑的地方
1,所给的图可能不连通,且不连通的时候不需要炸,输出0
2,当所要去炸的桥上的守卫数=0时,需要输出1而不是0
3,有重边
我的思路很简单,如果有重边的话那么就一定不是桥,那么只需要给一个特别一点值,在dfs里面更新的时候判断如果是这个特别的值就可以跳过了。在网上搜的题解都是转成有向图的做法,每条无向边转成两条有向边,..我还不是很懂..以后再回来看吧
//*我的代码*//#include<cstdio>#include<cstring>#include<vector>using namespace std;const int maxn=1500+10;const int INF = 100000000;int ans;int n,m;int dfs_clock;//时钟,每访问一个节点增1vector<int> G[maxn];//G[i]表示i节点邻接的所有节点int pre[maxn];//pre[i]表示i节点被第一次访问到的时间戳,若pre[i]==0表示i还未被访问int low[maxn];//low[i]表示i节点及其后代能通过反向边连回的最早的祖先的pre值bool iscut[maxn];//标记i节点是不是一个割点int adj[maxn][maxn];int pointnum;//求出以u为根节点(u在DFS树中的父节点是fa)的树的所有割顶和桥//初始调用为dfs(root,-1);int dfs(int u,int fa){ int lowu=pre[u]=++dfs_clock; int child=0; //子节点数目 for(int i=0; i<G[u].size(); i++) { int v=G[u][i]; if(!pre[v]) { child++;//未访问过的节点才能算是u的孩子 int lowv=dfs(v,u); lowu=min(lowu,lowv); if(lowv>=pre[u]) { iscut[u]=true; //u点是割顶 if(lowv>pre[u] && adj[u][v]!=-2) //(u,v)边是桥 ans = min(ans,adj[u][v]); } } else if(pre[v]<pre[u] && v!=fa)//v!=fa确保了(u,v)是从u到v的反向边 { lowu=min(lowu,pre[v]); } } if(fa<0 && child==1 ) iscut[u]=false;//u若是根且孩子数<=1,那u就不是割顶pointnum++; return low[u]=lowu;}int main(){ while(scanf("%d%d",&n,&m)==2&&n) { dfs_clock=0;//初始化时钟 memset(pre,0,sizeof(pre)); memset(iscut,0,sizeof(iscut));memset(adj,-1,sizeof(adj)); for(int i=0;i<=n;i++) G[i].clear(); for(int i=0;i<m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); // G[u].push_back(v); // G[v].push_back(u); if (adj[u][v]==-1){G[u].push_back(v);G[v].push_back(u);adj[u][v]=w;adj[v][u]=w;}else{adj[u][v]=-2;adj[v][u]=-2;} }ans = INF;pointnum=0;int flag=0; dfs(1,-1);//初始调用 for (int i = 1;i<=n;i++) //是否连通 if (!pre[i]){flag=1;break;}/*if (pointnum < n){flag = 1;}*/ if (flag) printf("0\n"); else if (ans == INF)printf("-1\n");else if (ans==0)printf("1\n");elseprintf("%d\n",ans); } return 0;}
//
一个大牛的做法,附上解释
分析:
本题的本质还是无向图求桥,且求得是守卫数目最少的那个桥。但是本题有3个点要注意:
1.所给的图可能不连通,且不连通的时候不需要炸,输出0.
2.当所要去炸的桥上的守卫数=0时,我们需要派的人数是1不是0.
3.任意两个节点u与v之间可能存在多条边。
对于上面的1与2点,我们在原始tarjan()函数运行完后加一些判断就能解决.
不过对于重边无向图,首先我们要用邻接表来保存图了(不能再用vector的邻接矩阵了).
然后之前无重边的时候我们都是用过fa来标记父节点的,如果u的儿子等于fa,那么直接跳过。即如果u不通过儿子连回fa的话,low[u]==pre[u]肯定>pre[fa]。现在本题其实u是可以通过另一条(fa,u)的边连回fa的,所以这里即使u不通过儿子连回fa的话,low[u]==也可以==pre[fa]。因为fa通过边1到u,u可以通过边2到fa。
所以本题把无向图转换成有向图来做:
把每条无向边分为两条有向边i与i+1,如果u通过边i到达了v,那么v中必然有一条边是i^1且可以通过该i^1边到u.所以如果在v节点遍历时到达i^1边时,我们直接跳过.
具体实现还是需要体会代码才能清晰.
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=1000+10;const int maxm=2*1000*1000+100;int n,m;int tot;int head[maxn];struct Edge{ int to,next,w;}edges[maxm];void add_edge(int u,int v,int w){ edges[tot]=(Edge){v,head[u],w}; head[u]=tot++; edges[tot]=(Edge){u,head[v],w}; head[v]=tot++;}int pre[maxn],low[maxn];int dfs_clock,point_num;int ans;void tarjan(int u,int E){ low[u]=pre[u]=++dfs_clock; for(int e=head[u];e!=-1;e=edges[e].next) { int v=edges[e].to; if(e==(E^1)) continue; if(!pre[v]) { tarjan(v,e); low[u]=min(low[u],low[v]); if(low[v]>pre[u]) ans=min(ans,edges[e].w); } else low[u]=min(low[u],pre[v]); } point_num++;}int main(){ while(scanf("%d%d",&n,&m)==2&&n) { ans=1000000; dfs_clock=point_num=tot=0; memset(pre,0,sizeof(pre)); memset(head,-1,sizeof(head)); for(int i=0;i<m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add_edge(u,v,w); } tarjan(1,-1); if(point_num<n) printf("0\n"); //图不连通,不用炸 else if(ans==1000000) printf("-1\n"); //图中无桥 else if(ans==0) printf("%d\n",1); //桥上兵为0 else printf("%d\n",ans); } return 0;}
- HDU 4738 Caocao's Bridges(重边无向图求桥)
- HDU 4738 Caocao's Bridges(重边无向图求桥)
- HDU 4738 Caocao's Bridges(重边无向图求桥)
- Hdu 4738 Caocao's Bridges (有重边无向图求桥)
- HDU 4738 Caocao's Bridges(无向图求桥)
- HDU 4738 Caocao's Bridges 有重边的无向图求桥
- hdu 4738 Caocao's Bridges
- hdu 4738 Caocao's Bridges
- hdu 4738 Caocao's Bridges
- HDU:4738 Caocao's Bridges
- HDU 4738 Caocao's Bridges
- HDU 4738 Caocao's Bridges
- hdu 4738 - Caocao's Bridges
- hdu 4738 Caocao's Bridges
- HDU-4738Caocao's Bridges
- HDU 4738-Caocao's Bridges-无向图找桥 DAG Tarjan
- HDU 4738 Caocao's Bridges 无向图割边(水)
- hdu 4738 Caocao's Bridges -有重边的无向图找桥
- 【Clojure】Clojure与Java的互操作形式
- 编译成功hadoop 纪念一下
- 关于我的咨询和技术服务
- nano命令
- freeRTOS学习1
- HDU 4738 Caocao's Bridges(重边无向图求桥)
- [C/C++]_[初级]_[static_cast,reinterpret_cast,dynimic_cast的使用场景和区别]
- C++11
- 单选选择RadioGroup
- 设计模式-状态模式
- 伸展树的原理及实现源代码(有图文详解和C++实现代码)
- Spring Security安全框架入门篇
- 最简单的基于FFmpeg的推流器(以推送RTMP为例)
- c# 写入数据到excel文件