//目录

《贪婪的动态规划》

  • 状态的定义与转移
  • 贪心思想对动态规划的优化

 

确定状态

  • 青蛙的烦恼 LSGDOJ 1852

题目描述

池塘中有n片荷叶恰好围成了一个凸多边形,有一只小青蛙恰好站在1号荷叶上,小青蛙想通过最短的路程遍历所有的荷叶(经过一个荷叶一次且仅一次),小青蛙可以从一片荷叶上跳到另外任意一片荷叶上。

输入

 第一行为整数n,荷叶的数量。
接下来n行,每行两个实数,为n个多边形的顶点坐标,按照顺时针方向给出。保证不会爆double。 

 

输出

遍历所有荷叶最短路程,请保留3位小数。 

样例输入

4 50.0 1.0 5.0 1.0 0.0 0.0 45.0 0.0

样例输出

50.211

提示

对于所有数据,0<n<=720 
 
分析:

LSGDOJ 1852 青蛙的烦恼

状态定义:

  • 从 i 点出发,顺时针or 逆时针 走 j 步的最少距离(最优解),但是状态转移很麻烦,首先第一维是 j,第二维是起点,但是状态转移很难表示,从 i 点出发,还走 j-1 步?不一定,可以从从其他点,而不是相邻的点转移而来。所以走了,或者要走的节点,没有表示到dp状态中,转移方程很难写出来,加一维枚举从哪里来,时间不允许。步数也难确定了,于是考虑别的状态定义。

  • 考虑顺序, 从 I 结点,访问 剩下的 i+1,然后走i+2,...,i+j-1的最优解。从 i+j-1 结点开始,访问 剩下的i, i + 1,i+2,...,i+j-2 的最优解。

有了访问的顺序定义,状态转移就得到是:

 

贪心思想体现于凸多边形走法,不存在交叉路线。

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1000;

struct  Node {
    double x,y;
}nodes[maxn];

double dist[maxn][maxn];
double dp[maxn][maxn][2];


int main(int argc, char const *argv[]) {

    freopen("in.txt","r",stdin);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%lf%lf",&nodes[i].x,&nodes[i].y);
    }


    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            dist[i][j] = sqrt((nodes[i].x-nodes[j].x)*(nodes[i].x-nodes[j].x)+(nodes[i].y-nodes[j].y)*(nodes[i].y-nodes[j].y));


    for (int i = 1; i <= n; ++i)
        dp[i][1][0] = dp[i][1][1] = 0;

    for(int j=2;j<=n;j++) {
        for(int i=1;i<=n;i++) {
            dp[i][j][0] = min(dist[i][i+1]+dp[i+1][j-1][0],dist[i][i+j-1]+dp[i+1][j-1][1]);
            dp[i][j][1] = min(dist[i][i+j-1]+dp[i][j-1][0],dist[i+j-1][i+j-2]+dp[i][j-1][1]);
        }
    }

    printf("%lf\n",min(dp[1][n][0],dp[1][n][1]));

    return 0;
}
View Code

 

 

 

 
posted @ 2017-08-09 10:12  小草的大树梦  阅读(381)  评论(0编辑  收藏  举报