POJ 1734 Sightseeing trip【floyd求最小环+记录路径】
2016-06-03 13:50
459 查看
Sightseeing trip
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");
}
}
Time Limit: 1000MS | | Memory Limit: 65536K | ||
Total Submissions: 6010 | | Accepted: 2324 | | Special Judge |
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");
}
}
相关文章推荐
- 单个和多个checkbox选中事件
- Android Studio 导入第三方库工程、jar 包和 so 库
- 如何解决Android软键盘盖住输入框的问题
- iOS开发iOS7状态栏文字颜色修改
- EF事务
- caffe的python接口封装原理与解析
- java 读写xml dom4j
- Django学习笔记--后台管理界面
- AndroidStudio常用快捷键整理
- 时间编程
- LeetCode 091: Decode Ways
- Bugly IOS Crash 符号表生成使用记录
- json串格式化代码
- iOS第三方资源
- 2的0-n方和
- 06.03
- linux(本机)配置域名
- linux 下第一个cordova android app
- Linux执行SHELL脚本的几种方法
- 超越之视频技术的核心要点总结