uva1347 tour

题目描述:———————————————————————————-uva1347 tour_第1张图片
“从左到右再回来”不太方便思考,可以改成:两个人同时从最左点出发,沿着两条不同
的路径走,最后都走到最右点,且除了起点和终点外其余每个点恰好被一个人经过。这样,
就可以用d(i,j)表示第一个人走到i,第二个人走到j,还需要走多长的距离。
状态如何转移呢?仔细思考后会发现:好像很难保证两个人不会走到相同的点。例如,
计算状态d(i,j)时,能不能让i走到i+1呢?不知道,因为从状态里看不出来i+1有没有被j走
过。换句话说,状态定义得不好,导致转移困难。
下面修改一下:d(i,j)表示1~max(i,j)全部走过,且两个人的当前位置分别是i和j,还需
要走多长的距离。不难发现d(i,j)=d(j,i),因此从现在开始规定在状态中i>j。这样,不管是
哪个人,下一步只能走到i+ 1 , i+2,…这些点。可是,如果走到i+2,情况变成了“1~i和i+
2,但是i+1没走过”,无法表示成状态!怎么办?禁止这样的决策!也就是说,只允许其中
一个人走到i+1,而不能走到i+2, i+3,…。换句话说,状态d(i,j)只能转移到d(i+1,j)和d(i+
1,i) (4) 。
可是这样做产生了一个问题:上述“霸道”的规定是否可能导致漏解呢?不会。因为如果
第一个人直接走到了i+2,那么它再也无法走到i+1了,只能靠第二个人走到i+1。既然如
此,现在就让第二个人走到i+1,并不会丢失解。
边界是d(n-1,j)=dist(n-1,n)+dist(j,n),其中dist(a,b)表示点a和b之间的距离。因为根据
定义,所有点都走过了,两个人只需直接走到终点。所求结果是dist(1,2)+d(2,1),因为第一
步一定是某个人走到了第二个点,根据定义,这就是d(2,1)。
状态总数有O(n 2 )个,每个状态的决策只有两个,因此总时间复杂度为O(n 2 )。

#include
#include
#include
#include
#include

#define maxn  1000+10
using namespace std;
int n;
struct node
{
    int x,y;
}loc[maxn];
double dp[maxn][maxn];
double dist[maxn][maxn];

void initial()
{   
    for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++)
    {
        double detx=(double)(loc[i].x-loc[j].x);
        double dety=(double)(loc[i].y-loc[j].y);
        double temp=detx*detx+dety*dety;
        dist[i][j]=dist[j][i]=sqrt(temp);
    }   
}

double fun(int i,int j)
{   
    double& ans=dp[i][j];
    if(ans>0)return ans;
    if(i==n-1)return ans=dist[i][n]+dist[j][n];

    double p1=fun(i+1,j)+dist[i][i+1];
    double p2=fun(i+1,i)+dist[j][i+1];              
    ans=min(p1,p2);  
    return ans;
}

void function(int n)
{

    for(int i=1;i<=n;i++)
    {
        cin>>loc[i].x>>loc[i].y;
    }
    initial();
    ostringstream oss;
    oss<2)<2,1)+dist[1][2]<string s=oss.str();
    cout<memset(dist,0,sizeof(dist));
    memset(dp,0,sizeof(dp));

}

int main()
{

    while(scanf("%d",&n)!=EOF)
    {
        function(n);
    }

}

你可能感兴趣的:(动态规划)