poj 1160 Post Office

动态规划

1.先考虑在1到n的村长里面放一个邮局的最优解,那么就是把邮局放在最中间的那个村庄处最优(若村庄数为偶数则最中间的村庄有两个哪个都可以)

2.当放m个邮局的时候,其他每个邮局相当于有一个控制范围,范围内的村庄离该邮局最近,那么m个邮局会把n个村庄分为m块,我们就是dp每一块,令每一块的值最优,以及加上还没有处理的大块的最优解,则是我们要的答案

dp[i][j]表示从1号到i号村庄放j个邮局的最优解

方程:dp[i][j]=min{ dp[k-1][j-1]+s[k][i] }   s[k][i]表示在k号村庄到i号村庄放1个邮局的最优解,也就是放在最中间

 

记忆化搜索

/*

dp[i][j]=min{ dp[k-1][j-1]+s[k][i] }

*/

#include <cstdio>

#include <cstring>

#define INF 0x3f3f3f3f

#define N 310

#define M 35

#define ABS(a,b) a-b>0?a-b:b-a

#define min(a,b) a<b?a:b



int dp[N][M],s[N][N],v[N],n,m;



int sum(int a , int b)

{

    int ans=0,mid=(a+b)>>1;

    for(int i=a; i<=b; i++)

        ans+=ABS(v[mid],v[i]);

    return ans;

}



int dfs(int i ,int j)

{

    int mid,c,k;

    if(j==1)

    {

        dp[i][j]=0;

        mid=(1+i)>>1;

        for(c=1; c<=i; c++)

            dp[i][j]+=ABS(v[mid],v[c]);

        return dp[i][j];

    }

    if(dp[i][j]!=-1) return dp[i][j];



    dp[i][j]=INF;

    for(k=i; k>=j; k--) //当前分块的右边界

    {

        if(!s[k][i]) //还没有被计算过

            s[k][i]=sum(k,i);

        dp[k-1][j-1]=dfs(k-1,j-1);

        dp[i][j]=min(dp[i][j],dp[k-1][j-1]+s[k][i]);

    }

    return dp[i][j];

}



int main()

{

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        for(int i=1; i<=n; i++) scanf("%d",&v[i]);

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

        memset(s,0,sizeof(s));

        dfs(n,m);

        printf("%d\n",dp[n][m]);

    }

    return 0;

}

 

递推

/*

递推版本,应该按照j从小往大递推

dp[i][j]=min{ dp[k-1][j-1]+s[k][i] }

*/



#include <cstdio>

#include <cstring>

#define INF 0x3f3f3f3f

#define N 310

#define M 35

#define ABS(a,b) a-b>0?a-b:b-a

#define min(a,b) a<b?a:b



int dp[N][M],s[N][N],v[N],n,m;



int sum(int a ,int b)

{

    int ans=0,mid=(a+b)>>1;

    for(int i=a; i<=b; i++)

        ans+=ABS(v[mid],v[i]);

    return ans;

}



int main()

{

    while(scanf("%d%d",&n,&m)!=EOF)

    {

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

            scanf("%d",&v[i]);

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

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

                s[i][j]=sum(i,j);

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

            dp[i][1]=s[1][i];



        for(int j=2; j<=m; j++)

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

            {

                dp[i][j]=INF;

                for(int k=i; k>=j; k--)

                    dp[i][j]=min(dp[i][j],dp[k-1][j-1]+s[k][i]);

            }

        printf("%d\n",dp[n][m]);

    }

    return 0;

}

 

你可能感兴趣的:(Office)