您的位置:首页 > 其它

最短路径(paths)题解,,,水博客

2017-08-18 21:15 357 查看

题目描述:

平面内给出 n 个点,记横坐标最小的点为 A,最大的点为 B,现在小 Y 想要知道在
每个点经过一次(A 点两次)的情况下从 A 走到 B,再回到 A 的最短路径。但他是个强
迫症患者,他有许多奇奇怪怪的要求与限制条件:
1.从 A 走到 B 时,只能由横坐标小的点走到大的点。
2.由 B 回到 A 时,只能由横坐标大的点走到小的点。
3.有两个特殊点 b1 和 b2, b1 在 0 到 n-1 的路上,b2 在 n-1 到 0 的路上。
请你帮他解决这个问题助他治疗吧!


输入格式:

第一行三个整数 n,b1,b2,( 0 < b1,b2 < n-1 且 b1 <> b2)。n 表示点数,从 0 到 n-1 编号,b1 和 b2 为两个特殊点的编号。
以下 n 行,每行两个整数 x、y 表示该点的坐标(0 <= x,y <= 2000),从 0 号点顺序给出。Doctor Gao 为了方便他的治疗,已经将给出的点按 x 增序排好了。


输出格式:

输出仅一行,即最短路径长度(精确到小数点后面 2 位)


样例输入:

5 1 3
1 3
3 4
4 1
7 5
8 3


样例输出:

18.18


简析:

题目大意是:给定n个点及其坐标,要求从起点和终点相向而行,使得总距离最短,并要求包含各自的指定点,且除1,n两点外,不能包含相同点。
首先,为了方便,我们将 从n向1出发的路线视为从1向n的路线,并将点的编号加一(我实在不喜欢0到n-1)。
然后,本人用dp做的。数组f[i][j]表示线路一到达i点,线路二到达j点时的总路径长度。
为了保证不出现到达同一个点的情况,同时保证每一个点都用上,我们事先找出一个目标点,再用现在的状态去更新,来判断这个点应该加入哪一条线路,规定目标点的计算方式为 max(i,j)+1。
因此,转移方程为:(dis[i][j]表示i,j间的距离
int k=max(i,j)+1;
f[1][1]=0;
f[i][k]= min(f[i][k],f[i][j]+dis[j][k])
f[k][j]= min(f[k][j],f[i][j]+dis[i][k])
当然,要考虑一些特殊情况,例如b1,b2点,k=max(i,j)+1时,(i==n||j==n)。


代码 :

#include<stdio.h>
#include<string.h>
#include<math.h>
#define max(a,b) a>=b?a:b
#define min(a,b) a>=b?b:a
int scan(){             //读入优化
int x=0;
char c=getchar();
while(c>'9'||c<'0')
c=getchar();
while(c>='0'&&c<='9')
x=(x<<1)+(x<<3)+c-'0',
c=getchar();
return x;
}
struct node{
int x,y;
};
int n,b1,b2;
node poi[1010];
double dis(int i,int j){
int x=(poi[i].x-poi[j].x)*(poi[i].x-poi[j].x);
int y=(poi[i].y-poi[j].y)*(poi[i].y-poi[j].y);
return sqrt(x*1.0+y*1.0);
}
double d[1010][1010],f[1010][1010];
int main(){
n=scan();
b1=scan()+1;b2=scan()+1;
for(int i=1;i<=n;i++){
poi[i].x=scan();
poi[i].y=scan();
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
d[i][j]=d[j][i]=dis(i,j);
f[i][j]=20000010.0;
}
f[1][1]=0.0;  //都在起点时距离为0
//已经将从n到1视为从1到n
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(i!=j||i==1){
int k= max(i,j) ;
k++;
if(k==n+1){ //线路一或线路二到达终点
if(i!=n)
f

= min(f

,f[i][j]+d[i]
);
if(j!=n)
f

= min(f

,f[i][j]+d[j]
);
continue;
}
if(k!=b1)  //b1只能在线路一,因此,将k加入线路二时,要看一下k是不是b1
f[i][k]= min(f[i][k],f[i][j]+d[j][k]);
if(k!=b2)  //同理
f[k][j]= min(f[k][j],f[i][j]+d[i][k]);
}
}
printf("%.2lf",f

);  //保留两位小数
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  最短路 paths