现在的位置: 首页 > 综合 > 正文

POJ 1160 Post Office

2018年04月25日 ⁄ 综合 ⁄ 共 1113字 ⁄ 字号 评论关闭

题意:给定n(n<=300)个在一维坐标系下的村庄,想从中挑选m(m<=30)个作为邮局,使得每个村庄到最近的邮局的距离和最小。

题解:想到dp,因为dp的值和当前状态的最后一个post office的位置有关系,开始想到dp[i][j][k]代表在前i个村庄中选择j个post office最后一个post office在位置k的
          最小花费,但是转移需要很大的时间复杂度,然后想dp[i][j]代表在前i个村庄中选择j个post office的最小花费,这样的话需要枚举最后一个office和倒数第二个
          office的管辖分界线,同时需要预处理出来在[i , j]村庄内选一个office的最小花费,将office放到(i+j)/2的位置即可。

Sure原创,转载请注明出处。

#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
const int inf = 1 << 29;
const int maxn = 302;
const int maxm = 32;
int pos[maxn],sum[maxn],dp[maxn][maxm],map[maxn][maxn];
int m,n;

inline int MIN(int a,int b)
{
    return a < b ? a : b;
}

void read()
{
    sum[0] = 0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&pos[i]);
        sum[i] = sum[i-1] + pos[i];
    }
    return;
}

void make()
{
    for(int i=1;i<=n;i++)
    {
        map[i][i] = 0;
        for(int j=i+1;j<=n;j++)
        {
            int p = (i + j) / 2;
            int val = sum[j] + sum[i-1] - sum[p] * 2;
            if(((i + j) & 1) == 0) val += pos[p];
            map[i][j] = map[j][i] = val;
        }
    }
    return;
}

void solve()
{
    for(int i=1;i<=n;i++)
    {
        dp[i][1] = map[1][i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=2;j<=m;j++)
        {
            dp[i][j] = dp[i][j-1];
            for(int k=1;k<i;k++)
            {
                dp[i][j] = MIN(dp[i][j] , dp[k][j-1] + map[k+1][i]);
            }
        }
    }
    printf("%d\n",dp[n][m]);
    return;
}

int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        read();
        make();
        solve();
    }
    return 0;
}

抱歉!评论已关闭.