您的位置:首页 > 其它

POJ 1734 Sightseeing trip【floyd求最小环+记录路径】

2016-06-03 13:50 459 查看
Sightseeing trip
Time Limit: 1000MS

 

Memory Limit: 65536K

Total Submissions: 6010

 

Accepted: 2324

 

Special Judge

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

Source

CEOI 1999

 

思路:
1、floyd求最小环。

首先,理解Floyd算法是按照点的编号增加的顺序更新最短路径的,因为Floyd算法基于动态规划思想,动态规划过程必定存在一个顺序,这里的顺序就是节点编号增加的顺序。那么如果存在这个最小环,会在这个环中的编号最大的那个点u更新之前发现这个环,也就是说,当u点被拿来更新从i到j的最短路径时,我们就能够发现这个闭合环路,发现的方法也不难理解,if(dis【i】【j】+map【j】【u】+map【u】【i】<INF)那么就说明以i到j的一条路径加上j到u这条边,加上u到i这条边,就能够组成一个环路。那么我们就在floyd实现的代码上稍加改变就可以求得这个最小环。

2、我们可以逆向考虑这个问题,假设现在我们已经进行完floyd的过程了,dis【i】【j】已经是从i到j的最短路径值了,那么如果我们设定一个数组:pre【i】【j】来记录其路径的话,有这样一个方法:

首先我们能够理解,无论对dis【i】【j】这条路径上一共用多少个点更新过这个值,最后一步更新一定是这样的:dis【i】【j】=dis【i】【k】+dis【k】【j】,我们不妨拿出一个栗子来说:

对于dis【1】【5】,假如其最后一次更新是这样的:

dis【1】【5】=dis【1】【4】+dis【4】【5】,

其dis【1】【4】的最后一步更新为:

dis【1】【4】=dis【1】【2】+dis【2】【4】;

我们不难写出其路径:1 2 4 5.我们这里注意,起点终点就是dis【i】【j】中的i,j,那么2和4要如何记录呢?我们可以对其dis【i】【j】最后一次更新的点进行记录,也就是说:pre【1】【5】=4;pre【1】【4】=2;这个时候,我们发现5 4 2之间有相关联:2=pre【1】【pre【1】【5】】;那么我们不难想出,对于记录路径,我们可以回溯找各个节点。

我们将pre【i】【j】初始化为i,当其被更新的时候,我们都记录下来那个节点,回溯即可。

具体实现,我们仔细分析代码就能理解。

AC代码:

#include<stdio.h>
#include<string.h>
using namespace std;
int map[1005][1005];
int dis[1005][1005];
int pre[1005][1005];
int ans[1005];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
map[i][j]=0x7ffffff;
dis[i][j]=0x7ffffff;
pre[i][j]=i;
}
}
for(int i=0;i<m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
x--;y--;
if(map[x][y]>w)
{
map[x][y]=map[y][x]=w;
dis[x][y]=dis[y][x]=w;
}
}
int cont=0;
int minn=0x7ffffff;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=j+1;k<n;k++)
{
if(dis[j][k]+map[k][i]+map[i][j]<minn)
{
minn=dis[j][k]+map[k][i]+map[i][j];
cont=0;
ans[cont++]=i;
ans[cont++]=j;
int s=k,e=j;
while(1)//回溯记录路径。
{
if(pre[s][e]==s)break;
ans[cont++]=pre[s][e];
e=pre[s][e];
}
ans[cont++]=k;
}
}
}
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
if(dis[j][k]>dis[j][i]+dis[i][k])
{
dis[j][k]=dis[j][i]+dis[i][k];
pre[j][k]=pre[i][k];
}
}
}
}
if(minn==0x7ffffff)
{
printf("No solution.\n");//别忘记输出无环的情况。
}
for(int i=0;i<cont;i++)
{
if(i==0)printf("%d",ans[i]+1);
else
printf(" %d",ans[i]+1);
}
printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ 1734 pku 1734