POJ 1734 Sightseeing trip

来源:互联网 发布:淘宝购物被骗找网警 编辑:程序博客网 时间:2024/06/05 11:29

题目大意:
在一张无向图上求一个不是自环的最小环


分析:
好难呀,如果只求最小环的权值我还勉强可以写出来,但是加上记录路径就完全不会了,觉得自己弱爆了O(≧口≦)O
先说怎么求最小环:
我们考虑这样一个问题,怎么求最短路?很简单Floyd、dijkstra,etc.,那么最小环呢?所以我们就要先考虑环和路径之间有什么关系,很明显,环是由路径连接而成的,详细来说,一个i~i的环可以拆成三条边i~k的直接路径,k~j的直接路径以及i~j的最短路径。为什么要这么拆呢?为什么不拆成两条最短路径或者三条最短路径呢?这就是Floyd的功劳了,我们考虑Floyd是怎么求最短路的,dis[i][j]=min(dis[i][k]+dis[k][j]),我们是通过枚举ij之间的中间点k来更新ij之间的最短路径,所以我们也可以通过枚举点k来更新ii之间的最短路径,也就是环,但是直接更新肯定不行,因为我们无法保证我们求出的ij之间的最短路不包含k,所以怎么办呢?我们可以强制要求k是环上编号最大的点,然后通过枚举k来更新最小环。
接下来就是很难想到的路径记录问题了:我们可以发现,一条从i到j的路径,如果看成有向边的话,每个点都有在这条路径上的唯一father节点,有了这个想法,这个问题就很好解决了,我们记录一下ij之间的最短路径上每个节点的pre值,在更新dis的时候,更新pre


代码如下:

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#define inf 0x7ffffff//注意inf不能开太小会WA太大会REusing namespace std;const int maxn=100+5;int mp[maxn][maxn],n,m,path[maxn],cnt,pre[maxn][maxn],dis[maxn][maxn],ans;inline int read(){    char ch=getchar();    int f=1,x=0;    while(!(ch>='0'&&ch<='9')){        if(ch=='-')            f=-1;        ch=getchar();    }    while(ch>='0'&&ch<='9')        x=x*10+ch-'0',ch=getchar();    return f*x;}signed main(void){    while(scanf("%d%d",&n,&m)!=EOF){        cnt=0,ans=inf;        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                pre[i][j]=i,mp[i][j]=dis[i][j]=inf;        for(int i=1,x,y,z;i<=m;i++)            x=read(),y=read(),z=read(),dis[x][y]=dis[y][x]=mp[x][y]=mp[y][x]=min(mp[x][y],z);        for(int k=1;k<=n;k++){            for(int i=1;i<k;i++)                for(int j=i+1;j<k;j++)                    if(ans>mp[i][k]+mp[k][j]+dis[i][j]){                        ans=mp[i][k]+mp[k][j]+dis[i][j];//dis--最短距离,mp---直接距离                         cnt=0;                        int tmp=j;                        while(tmp!=i){                            path[++cnt]=tmp;                            tmp=pre[i][tmp];                                                }                        path[++cnt]=i,path[++cnt]=k;                    }            for(int i=1;i<=n;i++)                for(int j=1;j<=n;j++)                    if(dis[i][j]>dis[i][k]+dis[k][j]){                        dis[i][j]=dis[i][k]+dis[k][j];                        pre[i][j]=pre[k][j];                    }        }        if(ans==inf)            printf("No solution.\n");        else{            for(int i=1;i<=cnt;i++)                cout<<path[i]<<" ";            cout<<endl;        }    }    return 0;}

by >o< neighthorn

0 0
原创粉丝点击