洛谷P6175 无向图的最小环问题

题目传送门

题目大意

求无向图的最小环,\(1\leq n\leq 100\)\(1\leq m\leq5 \times 10^{3}\)\(1\leq d\leq 10^{5}(n\)为顶点数,\(m\)为边数,\(d\)为边权\()\)

Solution1

Floyd求最小环

时间复杂度\(O(n^3)\)

设一个环中编号最大的顶点为\(k\),则这个环的权值和可表示为\(d[i][j]+w[i][k]+w[k][j]\)\(i\)\(j\)为环中与\(k\)相邻的顶点,\(d[i][j]\)表示\(i\)\(j\)不经过\(k\)的最短路长度。

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
template<typename T>void read(T& x){
    int f=0;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    if(f)x=-x;
}
int n,m,ans=INF;
int w[105][105],d[105][105];
int main(){
    int u,v,ww;
    read(n),read(m);
    memset(d,INF,sizeof(d));
    memset(w,INF,sizeof(w));
    for(int i=1;i<=n;++i)d[i][i]=0;
    for(int i=1;i<=m;++i){
        read(u),read(v),read(ww);
        d[u][v]=d[v][u]=w[u][v]=w[v][u]=min(w[u][v],ww);//处理重边 
    }
    for(int k=1;k<=n;++k){
        for(int i=1;i<k;++i)
            for(int j=1;j<k;++j)
                if(i!=j&&d[i][j]!=INF&&w[i][k]!=INF&&w[k][j]!=INF&&d[i][j]+w[i][k]+w[k][j]<ans)//注意要i!=j,否则构不成环 
                    ans=d[i][j]+w[i][k]+w[k][j];//此处的d[i][j]表示从i到j不经过k的最短路长度 
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
    }
    if(ans<INF)printf("%d",ans);
    else printf("No solution.");
    
    return 0;
}

Solution2

Dijkstra

时间复杂度\(O(m^2logm)\)\((\)实际上跑不满,剪枝后很快\()\)

枚举边\(i-j\),环和即为\(d[i][j]+w[i][j]\),用\(Dijkstra\)\(d[i][j]\)

要记得剪枝,否则会\(TLE\)

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
template<typename T>void read(T&x){
    int f=0;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    if(f)x=-x;
}
int n,m,ans=INF;
int w[105][105],d[105],vis[105];
int u[5005],v[5003];
struct node{
    int d,x;
    node(int d,int x):d(d),x(x){}
    bool operator < (const node& a)const{
        return d>a.d;
    }
};
int dij(int s,int t){
    priority_queue<node>q;
    memset(d,INF,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[s]=0;
    q.push(node(0,s));
    while(!q.empty()){
        node u=q.top();q.pop();
        if(vis[u.x])continue;
        vis[u.x]=1;
        if(d[u.x]+w[s][t]>ans)continue;//要剪枝 
        for(int i=1;i<=n;++i){
            if((u.x!=s||i!=t)&&(u.x!=t||i!=s)&&w[u.x][i]!=INF&&d[i]>d[u.x]+w[u.x][i]){//不能经过s-t这条边 
                d[i]=d[u.x]+w[u.x][i];
                q.push(node(d[i],i));
            }
        }
    }
    return d[t]; 
}
int main(){
    int u1,v1,ww;
    read(n),read(m);
    memset(w,INF,sizeof(w));
    for(int i=1;i<=m;++i){
        read(u1),read(v1),read(ww);
        u[i]=u1;
        v[i]=v1;
        w[u1][v1]=w[v1][u1]=min(w[u1][v1],ww);//处理重边 
    }    
    for(int i=1;i<=m;++i){
        int temp=dij(u[i],v[i]);
        if(temp!=INF)
            ans=min(ans,temp+w[u[i]][v[i]]);
    }
    if(ans!=INF)printf("%d",ans);
    else printf("No solution.");
    return 0;
}
posted @ 2021-01-20 23:47  lzc2001  阅读(108)  评论(0)    收藏  举报