码迷,mamicode.com
首页 > 其他好文 > 详细

最小环

时间:2020-07-06 12:49:25      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:ons   pre   names   存在   测试   front   tput   void   一个   

最小环(Tarjan \(\star?\))

  • 旅游区可以表示为一张由 \(n\) 个节点 \(m\) 条边组成无向图。我故地重游,却发现自己只想尽快地结束这次旅游。
  • 我从景区的出发点(即 \(1\) 号节点)出发,却只想找出最短的一条回路重新回到出发点,并且中途不重复经过任意一条边。即:我想找出从出发点到出发点的小环。

Input

  • 每个测试点有多组测试数据。
  • 第一行有一个正整数\(T, (T≤ 10)\)表示数据组数。
  • 接下来对于每组数据,第一行有两个正整数 \(n,m, (n\le 10^4,m ≤ 4\times 10^4\)) 分别代表图的点数和边数。
  • 接下来有\(m\)行,每行三个整数\(u,v,d\)表示\(u,v\)之间存在一条长度为 \(d, (d ≤ 10^3)\)的路径。
  • 保证不存在重边,自环。

Output

  • 对于每组测试数据,输出题目中所求的最小环的长度。
  • 无解输出 \(-1\)

Sample Input

2
3 3
1 2 1
2 3 1
3 1 1
4 5
1 2 2
2 3 2
3 4 2
1 4 2
1 3 5

Sample Output

3
8

Hint

  • 来源:\(hzoi2018\ NOIP\)模拟测试 \(6\) 《那一天她离我而去》

分析

  • 我们发现我们可以把与 \(1\) 号节点相连的所有节点取出,如果我们把最小环在 \(1\) 号节点处断开,那么最小环断成的链一定是以这些节点中的某一个节点作为起点,另一个节点作为终点的一条路路径。

Code

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4+5,maxm=4e4+5;
const int Inf=0x3f3f3f3f;
struct Node{int to,next,w;}e[maxm<<1];
int n,m,ans;
int head[maxn],len,dis[maxn];
bool vis[maxn];
priority_queue<pair<int, int> > q;
void Insert(int u,int v,int w){    
    e[len].to=v;e[len].w=w;e[len].next=head[u];head[u]=len++;
}
void Spfa(int x){
    memset(dis,0x3f,sizeof(dis));    
    memset(vis,0,sizeof(vis));
    queue<int> q;
    q.push(x);dis[x]=0;
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].w){
                dis[v]=dis[u]+e[i].w;
                if(!vis[v]){
                    q.push(v);vis[v]=1;
                }
            }
        }
    } 
}
void Solve(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        len=0;
        for(int i=1,u,v,w;i<=m;i++){
            scanf("%d%d%d",&u,&v,&w);
            Insert(u,v,w),Insert(v,u,w);
        }
        ans=Inf;
        for(int i=head[1];~i;i=e[i].next){
            int temp=e[i].w;
            e[i].w=e[i^1].w=Inf;//断掉一条邻接边
            Spfa(1);
            ans=std::min(ans,dis[e[i].to]+temp);
            e[i].w=e[i^1].w=temp;//续上
        }
        if(ans==Inf) ans=-1;
        printf("%d\n",ans);       
    }
}
int main(){
    Solve();
    return 0;
}

最小环

标签:ons   pre   names   存在   测试   front   tput   void   一个   

原文地址:https://www.cnblogs.com/hbhszxyb/p/13253985.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!