最短路径【DP】
题目大意:
求一个无向图的欧拉回路中最短路,要求去时和回时各经过一个特殊点。
5 1 3
1 3
3 4
4 1
7 5
8 3
18.18
思路:
欧拉回路?最短路?费用流?不,是。
要是没有两个特殊点的存在,这道题就是一个裸的欧拉回路。
但是有了这两个点,就是了。
当我们从点到达点时,要从点回点时,可以发现,这是一个无向图,从点到点的路径就是从点到点的路径!
那么这道题就转化为:求两条从点到点的边,要求这两条路径互不干涉,每一条路径经过一个特殊点,且要求路径长度之和最短。
设为第一条路径到达点,第二条路径到达点的最短路径和,那么就有
最终任意一条路径到达终点时
代码:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
double f[1011][1011],x[1011],y[1011],dis[1011][1011];
int n,b1,b2,k;
int main()
{
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
scanf("%d%d%d",&n,&b1,&b2);
for (int i=1;i<=n;i++)
{
scanf("%lf%lf",&x[i],&y[i]);
for (int j=1;j<i;j++)
dis[i][j]=dis[j][i]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); //求直线距离
}
for (int i=0;i<=n;i++)
for (int j=0;j<=n;j++)
f[i][j]=2147483647; //初始化
f[1][1]=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
if (i==j&&i>1) continue; //判断
k=max(i,j)+1;
if (k>n) //到达终点
{
if (i<n) f[n][n]=min(f[n][n],f[i][j]+dis[i][n]);
if (j<n) f[n][n]=min(f[n][n],f[i][j]+dis[j][n]);
}
else //没到达终点
{
if (k!=b2+1) f[k][j]=min(f[k][j],f[i][j]+dis[i][k]);
if (k!=b1+1) f[i][k]=min(f[i][k],f[i][j]+dis[j][k]);
}
}
printf("%0.2lf\n",f[n][n]);
return 0;
}