您的位置:首页 > 理论基础 > 计算机网络

HDU 4765 Tsp 2013长春网络赛G题 DP

2017-07-24 15:21 316 查看
第一次看这个题的时候,没有完全的弄清楚给出的三个条件,导致理解出现偏差,之后又重新理了一下题意,终于搞清楚它的意思。

题意:卡车司机要送n件货物,从i+点收货,送到i-点,卡车就是一个栈,后收的货物要先送。

重点就是这3句话+Mo cannot visit any location more than once.

- Mo can't Go to location j+ from i+ if j > i;

- Mo can't go to location j- from i- if j < i;

- If Mo has visited location i-, location j+ will be removed from the world and cannot be visited any more if j < i.

然后找最短路径。

分析:想了很久,最后的dp复杂度很高,大概是n^4的,AC的程序也是800+ms险过。不知道大牛们都是怎么写的,快的可以几十毫秒过的。

dp[i][head][tail]表示当前在i+点,要收货,送货的区间是[head,tail],最后达到tail-点的最短路径。

那这个过程大致就变成了i+点—>j+(head<=j<i)点—>dp[j][head][i-1],达到(i-1)-点—>i-点—>k+点(i<k<=tail)—>dp[k][i+1][tail],到达tail-点。

代码:

#include <iostream>

#include <stdio.h>

#include <string.h>

#include <cmath>

using namespace std;

const int maxn=110;

int d[maxn*2][2];

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

int tag[maxn][maxn][maxn][2];

int n;

double dis(int i,int j)

{

    return sqrt((double)(d[i][0]-d[j][0])*(d[i][0]-d[j][0])+(d[i][1]-d[j][1])*(d[i][1]-d[j][1]));

}

void pre()

{

    for (int i=1;i<=n;i++)

        scanf("%d%d%d%d",&d[i][0],&d[i][1],&d[i+n][0],&d[i+n][1]);

    for (int i=1;i<=2*n;i++)

    for (int j=1;j<=2*n;j++)

    dist[i][j]=dis(i,j);

}

void find(int i,int head,int tail)

{

    double front=-1,behind=-1;

    if (i>head)//前面还有点,要继续装;//从i+走到i-;

    {

        for (int j=head;j<i;j++)//下一个走的点是j;

        {

            if (tag[j][head][i-1][0]==-1)

            find(j,head,i-1);

            if (front==-1||front>dist[i][j]+dp[j][head][i-1]+dist[i-1+n][i+n])

            {

                front=dist[i][j]+dp[j][head][i-1]+dist[i-1+n][i+n];

                tag[i][head][tail][0]=j;//标记这个状态下,往前走选择j点;

            }

        }

    }

    else

    {

        front=dist[i][i+n];

        tag[i][head][tail][0]=i;

    }

    if (i<tail)//到i-以后还要装;//从i-到tail-;

    {

        for (int k=i+1;k<=tail;k++)//下一个走的点是k;

        {

            if (tag[k][i+1][tail][0]==-1)

            find(k,i+1,tail);

            if (behind==-1||behind>dist[i+n][k]+dp[k][i+1][tail])

            {

                    behind=dist[i+n][k]+dp[k][i+1][tail];

                    tag[i][head][tail][1]=k;//标记这个状态下,往后走选择k点;

            }

        }

    }

    else

    {

        behind=0;

    }

    dp[i][head][tail]=front+behind;

    return;

}

void dfs(int i,int head,int tail)

{

    printf("%d+ ",i);

    if (i>head)

    {

        dfs(tag[i][head][tail][0],head,i-1);

    }

    if (i<n)

    printf("%d- ",i);

    else printf("%d-\n",i);

    if (i<tail)

    {

        dfs(tag[i][head][tail][1],i+1,tail);

    }

}

int main()

{

    //freopen("in.txt","r",stdin);

    while (~scanf("%d",&n))

    {

        pre();

        memset(tag,-1,sizeof(tag));

        int star;

        int minn=-1;

        for (int i=1;i<=n;i++)

        {

            find(i,1,n);

            if (minn==-1||minn>dp[i][1]
)

            {

                minn=dp[i][1]
;

                star=i;

            }

        }

        dfs(star,1,n);

    }

    return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: