ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

WOJ#3836 Sightseeing Trip

2019-11-13 15:53:33  阅读:260  来源: 互联网

标签:输出 3836 cn int 最小 son while Trip Sightseeing


描述

  给定一张无向图,求图中一个至少包含 3 个点的环,环上的节点不重复,并且环上的边的长度之和最小。该问题称为无向图的最小环问题。在本题中,你需要输出最小环的方案,若最小环不唯一,输出任意一个均可。若无解,输出 No solution.。图的节点数不超过 100 。

输入

第一行两个正整数 n,m 表示点数和边数。

接下来 m 行,每行三个正整数 x,y,z ,表示节点 x,y 之间有一条长度为 z 的边。

输出

输出一个最小环的方案:按环上顺序输出最小环上的点。若最小环不唯一,输出任意一个均可。若无解,输出 No solution.

样例输入

5 7
1 4 1
1 3 300
3 1 10
1 2 16
2 3 100
2 5 15
5 3 20

样例输出

1 3 5 2

标签

CEOI1999

题解

  其实这道题可以用Floyd。

  容易知道,树加上一条非树边可以形成环。利用这个性质,我们可以先求出一棵最小生成树,然后通过枚举每一条非树边求出加上它之后所形成的环的大小并尝试更新答案。输出方案时直接在最小生成树上暴力跳就行了。时间复杂度O(mlogn)。

  代码:

#include<bits/stdc++.h>
using namespace std;
#define gc getchar
template<typename T>void read(T&cn){
    char c;int sig=1;
    while(!isdigit(c=gc())) if(c=='-') sig=-1;cn=c-48;
    while( isdigit(c=gc())) cn=cn*10+c-48;cn*=sig;
}
#define N 100010
#define INF 0x3f3f3f3f
int n,m;
namespace T{
    int num,f[N];
    struct node{
        int u,v,w,nxt;
    }e[N<<1];
    void add(int u,int v,int w){
        e[++num]=(node){u,v,w,f[u]};f[u]=num;
        e[++num]=(node){v,u,w,f[v]};f[v]=num;
    }
    //build graph
    int dep[N],dis[N],faz[N],siz[N],son[N],top[N];
    void dfs1(int u,int fa,int d){
        dep[u]=d;faz[u]=fa;siz[u]=1;
        for(int i=f[u];i;i=e[i].nxt){
            int v=e[i].v;
            if(v==fa) continue;
            dis[v]=dis[u]+e[i].w;dfs1(v,u,d+1);siz[u]+=siz[v];
            if(siz[v]>siz[son[u]]) son[u]=v; 
        }
    }
    void dfs2(int u,int st){
        top[u]=st;
        if(!son[u]) return;dfs2(son[u],st);
        for(int i=f[u];i;i=e[i].nxt){
            int v=e[i].v;
            if(v==faz[u]||v==son[u]) continue;
            dfs2(v,v);
        }
    }
    int LCA(int x,int y){
        int xx=top[x],yy=top[y];
        while(xx^yy){
            if(dep[xx]<dep[yy]){swap(xx,yy);swap(x,y);}
            x=faz[xx];xx=top[x];
        }
        return dep[x]<dep[y]?x:y;
    }
    //tree dissection
}
namespace G{
    struct node{
        int u,v,w;
    }e[N];
    bool operator < (node a,node b){return a.w<b.w;}
    //graph
    int fa[N];
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    int merge(int x,int y){
        int xx=find(x),yy=find(y);
        if(xx==yy) return 0;
        fa[xx]=yy; return 1;
    }
    //Disjoint-Set
    int vis[N];
    void kruskal(){
        sort(e+1,e+m+1);int cnt=0;
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=m;i++){
            int u=e[i].u,v=e[i].v;
            if(merge(u,v)){cnt++;vis[i]=1;T::add(u,v,e[i].w);}
            if(cnt==n-1) break;
        }
    }
    //mst
    int sum=INF,a,b,c;
    #define pb push_back
    vector<int>ans;
    void work(){
        read(n);read(m);
        for(int i=1;i<=m;i++){read(e[i].u);read(e[i].v);read(e[i].w);}
        kruskal();T::dfs1(1,0,1);T::dfs2(1,1);
        for(int i=1;i<=m;i++){
            if(vis[i]) continue;
            int u=e[i].u,v=e[i].v;
            if(T::dep[u]<T::dep[v]) swap(u,v);
            if(T::faz[u]==v||u==v) continue;
            int lca=T::LCA(u,v),tmp=T::dis[u]+T::dis[v]-(T::dis[lca]<<1)+e[i].w;
            if(sum>tmp){sum=tmp;a=u,b=v;c=lca;}
        }
        if(sum==INF){puts("No solution.");exit(0);}
        while(a^c){printf("%d ",a);a=T::faz[a];}printf("%d ",c);
        while(b^c){ans.pb(b);b=T::faz[b];}
        if(ans.size()) for(int i=ans.size()-1;~i;i--) printf("%d ",ans[i]);
    }
}
int main(){
    G::work();
    return 0;
}

 

标签:输出,3836,cn,int,最小,son,while,Trip,Sightseeing
来源: https://www.cnblogs.com/doyo2019/p/11850029.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有