【图论】Floyd找无向图最小环 poj 1734

Floyd求无向图最小环

算法思想

如果若干个点形成一个环,则该环对应的有限点集V一定含有最大编号的点Kmax,按编号小到大枚举这个最大点k。

枚举时,以k为外层循环,每层循环考虑:

只经过前k-1个点的i,j间最短路径d[i][j],连接i,k的边g[i][k],连接k,j的边g[k][j],若d[i][j]+g[i][k]+g[k][j]<mn,则更新最小环的长度,同时记录路径,该环路径包含了曾经的k-1个点中的最短路上的点,也包括i,j,k三点,放入答案数组中即可。

若要统计最小环的个数,则可以在mn==d[i][j]+g[i][k]+g[k][j]时计数,要注意,如果mn在后续被更新,该计数个数要重置。

变量定义

d[i][j]:从i到j的最短路径长

g[i][j]:连接i和j的最小边长(直接相连)

pos[i][j]:在Floyd中更新了i,j间最短路径的点

mn: 最小环的长度

代码 POJ 1734(模板题)

#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;

const int maxn=101;
const int _INF=0x7fffffff;
const int INF=_INF/3;
int n,m;
int d[maxn][maxn],g[maxn][maxn],pos[maxn][maxn];
int id,mn;
int path[maxn],cnt;

void floyd()
{
    mn=INF;
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<k;i++)
            for(int j=i+1;j<k;j++)
            {
                if(mn>d[i][j]+g[i][k]+g[k][j])
                {
                    mn=d[i][j]+g[i][k]+g[k][j];
                    cnt=0;
                    int t=i;
                    while(t!=j)
                    {
                        path[++cnt]=t;
                        t=pos[j][t];
                    }
                    path[++cnt]=j;
                    path[++cnt]=k;
                }
            }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                if(d[i][j]>d[i][k]+d[k][j])
                {
                    pos[i][j]=pos[k][j];//无向图,每次更新pos[i][j]即可(当循环至j=i,i=j时,pos[j][i]=pos[k][i] ) 
                    d[i][j]=d[i][k]+d[k][j];
                }
            }
    }
}

void init()
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            {
                pos[i][j]=i;
                if(i!=j)    g[i][j]=d[i][j]=INF;
                else    g[i][j]=d[i][j]=0;
            }
}

int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=m;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);
        if(c<g[x][y]) d[x][y]=d[y][x]=g[x][y]=g[y][x]=c;
    }
    floyd();
    if(mn==INF) printf("No solution.\n");
    else
    {
        for(int i=1;i<=cnt;i++) printf("%d ",path[i]);
    }
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/JWizard/p/11753842.html