zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    SQL删除多表关联数据的三种方法
    如何防范SQL注入攻击
    非关系型数据库和关系型数据库有哪些区别?
    Asp.Net生命周期的详解
    ASP与ASP.NET区别
    COOKIE和SESSION有什么区别?
    关于SQL数据库中cross join 和inner join用法上的区别?
    Java-编程规范与代码风格
    TCP 连接建立与关闭(三次握手与四次挥手)
    OSI 七层模型
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2946256.html
Copyright © 2011-2022 走看看