您的位置:首页 > 其它

poj 1734 Sightseeing trip (floyd求最小环并记录路径)

2015-11-23 13:37 447 查看
点击打开题目链接

Description
There is a travel agency in Adelton town on Zanzibar island. It has decided to offer its clients, besides many other attractions, sightseeing the town. To earn as much as possible from this attraction,
the agency has accepted a shrewd decision: it is necessary to find the shortest route which begins and ends at the same place. Your task is to write a program which finds such a route.

In the town there are N crossing points numbered from 1 to N and M two-way roads numbered from 1 to M. Two crossing points can be connected by multiple roads, but no road connects a crossing point with itself. Each sightseeing route is a sequence of road numbers
y_1, ..., y_k, k>2. The road y_i (1<=i<=k-1) connects crossing points x_i and x_{i+1}, the road y_k connects crossing points x_k and x_1. All the numbers x_1,...,x_k should be different.The length of the sightseeing route is the sum of the lengths of all roads
on the sightseeing route, i.e. L(y_1)+L(y_2)+...+L(y_k) where L(y_i) is the length of the road y_i (1<=i<=k). Your program has to find such a sightseeing route, the length of which is minimal, or to specify that it is not possible,because there is no sightseeing
route in the town.
Input
The first line of input contains two positive integers: the number of crossing points N<=100 and the number of roads M<=10000. Each of the next M lines describes one road. It contains 3 positive integers:
the number of its first crossing point, the number of the second one, and the length of the road (a positive integer less than 500).
Output
There is only one line in output. It contains either a string 'No solution.' in case there isn't any sightseeing route, or it contains the numbers of all crossing points on the shortest sightseeing
route in the order how to pass them (i.e. the numbers x_1 to x_k from our definition of a sightseeing route), separated by single spaces. If there are multiple sightseeing routes of the minimal length, you can output any one of them.
Sample Input
5 7
1 4 1
1 3 300
3 1 10
1 2 16
2 3 100
2 5 15
5 3 20

Sample Output
1 3 5 2
题意:
有n个城市,有m条路,每条路连接两个城市而且有一定的花费,你的任务是找出一条由起点开始又回到起点的路径,使得路径上所有的花费最小,并且这条路径至少有3个以上不同城市,假如从v1开始,那么v1->v2->....->vk,vk再回到v1,k要大于2,输出格式为v1 v2 ....vk
其中n<=100,m<=10000,每条路径花费不大于500;
分析:如果不输出路径,那么此题就是一个floyd求最小环的问题,但是此题需要输出的是最小环经过的点,所以我们就要在原来求最小环的基础上加一个数组记录路径,我们另外开一个数组pa[i][j]=x表示的是i->......->x->j,意思就是pa[i][j]存的是i->j这条路径上j的前面一个点是哪个。
很显然,初始化时pa[i][j]=i;
那么如何用dp转移呢,回顾一下求floyd求最短路时转移是这样的:如果dis[i][j]>dis[i][k]+dis[k][j],那么dis[i][j]=dis[i][k]+dis[k][j],我们可以在这个时候同时转移pa,使pa[i][j]=pa[k][j],仔细想一下是不是这样,i->j这条路径上倒数第二个经过的点就是k->j上倒数第二个经过的点,因为pa[i][k]和pa[k][j]已经求出来了的,所以直接转移。
转移完成了,接下来的工作就是该怎么记录答案并且输出答案。我们只需要在floyd求最小环记录答案的时候把路径记录下来。
具体操作代码实现:
#include<Stdio.h>
#include<string.h>
#include<algorithm>
#define inf 1e8
using namespace std;
int dis[110][110];///记录最短路
int pa[110][110];///记录i>j这条路径上倒数第二个经过的点
int ma[110][110];///记录原图
int ans[110];///记录路径(倒着的)
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dis[i][j]=ma[i][j]=inf;
pa[i][j]=i;
}
}
for(int i=1;i<=m;i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
if(ma[x][y]>c)///防止重边
{
ma[x][y]=dis[x][y]=c;
ma[y][x]=dis[y][x]=c;
}
}
int minn=inf,num;///num记录的是路径上点的个数
for(int k=1;k<=n;k++)
{
///下面这两个循环意思是以k为起点,看看有没有回到k点的路径,i和j表示的是和k点直接相连的不同的两个点,这样保证了这个换有三个点
for(int i=1;i<k;i++)
{
for(int j=i+1;j<k;j++)
{
if(minn>dis[i][j]+ma[k][i]+ma[k][j])
{
num=0;///每次找到更好的答案时便要重新记录路径
minn=dis[i][j]+ma[k][i]+ma[k][j];
int posi=i,posj=j;
ans[++num]=j;
while(1)///倒着记录路径,画个图自然明白
{
posj=pa[posi][posj];
num++;
ans[num]=posj;
if(posi==posj) break;
}
ans[++num]=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];
pa[i][j]=pa[k][j];
}
}
}
}
if(minn==inf)
{
puts("No solution.");
continue;
}
for(int i=num;i>=2;i--) printf("%d ",ans[i]);
printf("%d\n",ans[1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: