题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=38898
题意:有n个点的坐标(n<1000,并且坐标按x的递增顺序给出)你的任务是设计一条路线,从最左边出发走到最右边再返回。除了最左边的点和最右边的点,其余各个点只经过一次,且路径最短。
解法:请见紫书(算法竞赛入门经典 第二版) P269
总结:对于求最大和最小,并且是DAG。我们可以采用dp的思想。先写出更新方程,然后根据情况采用记忆化搜索或者刷表法更新。
AC:
#include <algorithm>
#include <string>
#include <iostream>
#include <string.h>
#include<stdio.h>
#include<cmath>
#include<vector>
using namespace std;
#define ll long long int
#define inf 1000000000
const int maxn = 1024;
struct ss
{
int x,y;
}st[maxn];
double dis[maxn][maxn],dp[maxn][maxn];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&st[i].x,&st[i].y);
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
int temp=(st[i].x-st[j].x)*(st[i].x-st[j].x)+(st[i].y-st[j].y)*(st[i].y-st[j].y);
dis[j][i]=dis[i][j]=sqrt(temp*1.000);
}
}
memset(dp,0,sizeof dp);
for(int i=1;i<n;i++)
{
dp[n-1][i]=dis[i][n]+dis[n-1][n];
}
for(int i=n-2;i>0;i--)
{
for(int j=1;j<i;j++)
{
dp[i][j]=min(dp[i+1][j]+dis[i][i+1],dp[i+1][i]+dis[i+1][j]);//更新方程
}
}
double ans=dp[2][1]+dis[1][2];
printf("%.2lf\n",ans);
}
}