题目传送门:【HDU 4738】
题目大意: 多组数据。给出一个含有 n 个点和 m 条边的无向图(1 ≤ n ≤ 1000,1 ≤ m ≤ n 2 ),现在,你要找出一条边,使得删除这条边之后,整个图变得不连通;找出满足的边里权值最小的那条边并输出结果,找不到则输出 -1。输入为两个 0 时结束。
题目分析:
模板题。题目大意已经十分明确,直接使用 Tarjan 算法求桥,然后维护最小权值即可。
具体操作为
void tarjan(int u,int fa) // fa代表之前走过来的边的编号
注意,本题要结合以下条件:每条边即使没人,也要派至少一个人去执行任务(题意说了的);如果一开始就是不连通的图,那么就不用派人去执行任务了,输出 0。(题意也说了的)
下面附上代码:
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- typedef long long LL;
- const int MX=1005;
- const int INF=0x3f3f3f3f;
- struct Edge{
- int to,next,num;
- }edge[MX*MX*2];
- int n,m,head[MX],now=1; //now设为1,方便之后异或
- int dfn[MX],low[MX],_index=0,mind=INF;
- bool vis[MX*MX*2];
- inline void adde(int u,int v,int w){
- edge[++now].to=v;
- edge[now].num=w;
- edge[now].next=head[u];
- head[u]=now;
- }
- void tarjan(int u,int fa){ //这里的 fa 表示的是上一条边
- dfn[u]=low[u]=++_index;
- int child=0;
- for (int i=head[u];i;i=edge[i].next){
- int v=edge[i].to;
- if (!dfn[v]){
- child++;
- tarjan(v,i);
- if (low[v]<low[u]){
- low[u]=low[v];
- }
- if (low[v]>dfn[u]){
- if (edge[i].num<mind)
- mind=edge[i].num;
- }
- } else if (dfn[v]<low[u] && fa!=(i^1)){ //求桥不能直接返回到u点
- low[u]=dfn[v];
- }
- }
- }
- void _init(){
- memset(dfn,0,sizeof(dfn));
- memset(head,0,sizeof(head));
- now=1,_index=0,mind=INF;
- }
- int main(){
- while (scanf(“%d%d”,&n,&m) && (n || m)){
- int a,b,w;
- for (int i=1;i<=m;i++){
- scanf(”%d%d%d”,&a,&b,&w);
- adde(a,b,w);
- adde(b,a,w);
- }
- tarjan(1,-1);
- for (int i=1;i<=n;i++)
- if (!dfn[i]){
- mind=-1;
- break;
- }
- if (mind==-1) printf(“0\n”); //图不连通
- else if (mind<INF) printf(“%d\n”,mind>0?mind:1); //至少需要 1 个人
- else printf(“-1\n”); //不存在桥
- _init();
- }
- return 0;
- }