zoukankan      html  css  js  c++  java
  • POJ_1485_dp

    题目描述:

      每组数据给n个点,点按一维坐标升序给出,要求划分成k块,在每一块中,取一个站,要求每个块中所有的点到站的距离的和的总和最小。

    思路:

      dp题,dp[i][j]表示i个点分成j块的最小距离,每一个dp[i][j]可以由前面的dp[x][j-1]推出,其中j-1 <= x <= i-1,前面j-1个分块再加上后面一块,便形成了i个点j个划分,在所有符合条件的划分中取最小值,更新dp[i][j]的值。这样的思路,我们还需要一个方法计算一个块中的距离最小值。当一个块中点的数量为奇数时,取中点为站,则距离最小,当数量为偶数时,去中间两个点的任意一个,距离最小,所以我们可以用(left+right)/2表示一个区间中的那个站点。因为结果要求输出最小值的具体划分以及站点,还需要一个pos数组储存每种情况的划分边界。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    #define MAX 1<<30;
    
    int a[205],dis[205][205],dp[205][35],pos[205][35][205];
    
    int main()
    {    
        int n,K,num = 0;
        while(~scanf("%d%d",&n,&K) && n && K)
        {
            num++;
            memset(pos,0,sizeof(pos));
            memset(dis,0,sizeof(dis));
            for(int i = 1;i <= n;i++)   scanf("%d",&a[i]);
            for(int i = 1;i <= n;i++)
            {
                dis[i][i] = 0;
                for(int j = i+1;j <= n;j++)
                {
                    int mid = (i+j)/2;
                    for(int k = i;k < mid;k++)  dis[i][j] += a[mid]-a[k];
                    for(int k = mid+1;k <= j;k++)   dis[i][j] += a[k]-a[mid];
                }
            }
            for(int i = 1;i <= n;i++)
            {
                dp[i][1] = dis[1][i];
                pos[i][1][i] = 1;
                for(int j = 2;j <= i;j++)   dp[i][j] = MAX;
            }
            for(int i = 2;i <= n;i++)
            {
                for(int j = 2;j <= min(i,K);j++)
                {
                    for(int k = j-1;k <= i-1;k++)
                    {
                        int temp = dp[k][j-1]+dis[k+1][i];
                        if(temp < dp[i][j])
                        {
                            dp[i][j] = temp;
                            for(int l = 1;l <= k;l++)
                            {
                                pos[i][j][l] = pos[k][j-1][l];
                            }
                            pos[i][j][i] = 1;
                        }
                    }
                }
            }
            printf("Chain %d
    ",num);
            int now = 1;
            for(int i = 1;i <= K;i++)
            {
                int left = now;
                for(;!pos[n][K][now];now++);
                int right = now++;
                if (left == right)
                {
                    printf("Depot %d at restaurant %d serves restaurant %d
    ",i,left,left);
                }
                else
                {
                    printf("Depot %d at restaurant %d serves restaurants %d to %d
    ",i,(left+right)/2,left,right);
                }
            }
            printf("Total distance sum = %d
    
    ",dp[n][K]);
    
        }
        return 0;
    }
  • 相关阅读:
    SVM理论之线性分类
    编写自己的sniffer(二)
    二叉树三种非递归遍历的区别
    SVM理论之最优超平面
    [转载] Linux的capability深入分析
    [转载] ftp的模式ACTIVE&PASSIVE
    Linux下压缩不包含路径信息的压缩包
    [ZzDW] 关于Java对象序列化您不知道的5件事
    [转载] Windows如何在cmd命令行中查看、修改、删除与添加、设置环境变量
    [攻略转载] 在飞机上睡觉的七大攻略
  • 原文地址:https://www.cnblogs.com/zhurb/p/5840026.html
Copyright © 2011-2022 走看看