zoukankan      html  css  js  c++  java
  • POJ 1160 Post Office

     POJ_1160

        我们可以用f[i][j]表示建好i个邮局时覆盖到第j个村庄的最优解,那么就可以得到f[i][j]=min{f[i-1][k]+w[k+1][j]}(k<j),其中w[x][y]表示建一个邮局覆盖x到y的村庄的距离和,w[x][y]可以事先预处理出来。

        这个题目还可以用四边形不等式去优化,实际上四边形不等式优化难点不在于应用,只是在K[i][j-1]<=k<=K[i+1][j]中去选择更新f[i][j]的k即可,比较复杂的部分就在于对k可以这样选择做出证明。

        一般四边形不等式的证明步骤如下:

        ①证明w为凸,这一步用黑书上的定理w为凸当且仅当w[i][j]+w[i+1][j+1]<=w[i][j+1]+w[i+1][j],这样只要说明w[i+1][j]-w[i][j]是关于j单调递减的即可。

        ②证明f为凸,这一步要利用①中的定理去证f[i][j]+f[i+1][j+1]<=f[i][j+1]+f[i+1][j],而证明的方法通常是利用w为凸的结论,先假设f[i][j+1]取得最优解是k为x,f[i+1][j]取得最优解时f[i+1][j]为y,然后分x<y和y<x两种情况,将f[i][j]和f[i+1][j+1]各按k=x或k=y拆开之后,将拆出的w应用四边形不等式,再将各项合并成f[i][j+1]+f[i+1][j]从而完成证明。

        ③证明K[i][j-1]<=K[i][j]<=K[i+1][j],证明K[i][j-1]<=K[i][j]时,要先假设f[i][j-1]取得最优解时k=y,然后利用x<=y<=j-1<j列一个四边形不等式,然后在不等式两边添加一定的项试图得到f[i][j-1](k=x)+f[i][j](k=y)<=f[i][j-1](k=y)+f[i][j](k=x),也就是f[i][j-1](k=x)-f[i][j-1](k=y)<= f[i][j](k=x)-f[i][j](k=y),这时我们就会发现因为f[i][j-1](k=y)<=f[i][j-1](k=x),那么一定有f[i][j](k=y)<=f[i][j](k=x),也就是说对于所有小于y的x,都会有f[i][j-1](k=y)<=f[i][j-1](k=x),那么也都会有f[i][j](k=y)<=f[i][j](k=x),因此令f[i][j]取得最优解的k一定不小于y,这样就完成了对K[i][j-1]<=K[i][j]的证明。对于K[i][j]<=K[i+1][j]的证明是类似的。

    //O(P*V^2)
    #include<stdio.h>
    #include<string.h>
    #define MAXD 310
    #define MAXP 40
    int N, P, f[MAXP][MAXD], w[MAXD][MAXD], a[MAXD];
    void init()
    {
    int i, j, k;
    for(i = 1; i <= N; i ++)
    {
    scanf("%d", &a[i]);
    w[i][i] = 0;
    }
    for(k = 1; k < N; k ++)
    for(i = 1; (j = i + k) <= N; i ++)
    w[i][j] = w[i][j - 1] + a[j] - a[(i + j) / 2];
    }
    void solve()
    {
    int i, j, k;
    memset(f, 0x3f, sizeof(f));
    f[0][0] = 0;
    for(i = 1; i <= P; i ++)
    for(j = i; j <= N; j ++)
    for(k = i - 1; k < j; k ++)
    if(f[i - 1][k] + w[k + 1][j] < f[i][j])
    f[i][j] = f[i - 1][k] + w[k + 1][j];
    printf("%d\n", f[P][N]);
    }
    int main()
    {
    while(scanf("%d%d", &N, &P) == 2)
    {
    init();
    solve();
    }
    return 0;
    }
    //四边形不等式优化dp
    #include<stdio.h>
    #include<string.h>
    #define MAXD 310
    #define MAXP 40
    #define INF 0x3f3f3f3f
    int N, P, f[MAXD][MAXD], A[MAXD], a[MAXD], K[MAXD][MAXD];
    void init()
    {
    int i, j, k;
    A[0] = 0;
    for(i = 1; i <= N; i ++)
    {
    scanf("%d", &a[i]);
    A[i] = A[i - 1] + a[i];
    }
    }
    int getw(int x, int y)
    {
    int t = (x + y) / 2;
    return A[y] - A[t] - (y - t) * a[t] + (t - x) * a[t] - (A[t - 1] - A[x - 1]);
    }
    void solve()
    {
    int i, j, k, p, t;
    for(i = 0; i <= N; i ++)
    {
    f[i][i] = 0;
    K[i][i] = i;
    }
    for(p = 1; p <= N - P; p ++)
    {
    for(i = 0; (j = i + p) <= N; i ++)
    f[i][j] = INF;
    for(i = 1; (j = i + p) <= N; i ++)
    {
    for(k = K[i][j - 1]; k <= K[i + 1][j]; k ++)
    if((t = f[i - 1][k - 1] + getw(k, j)) < f[i][j])
    {
    f[i][j] = t;
    K[i][j] = k;
    }
    }
    }
    printf("%d\n", f[P][N]);
    }
    int main()
    {
    while(scanf("%d%d", &N, &P) == 2)
    {
    init();
    solve();
    }
    return 0;
    }

     

  • 相关阅读:
    matplotlib数据可视化之柱形图
    xpath排坑记
    Leetcode 100. 相同的树
    Leetcode 173. 二叉搜索树迭代器
    Leetcode 199. 二叉树的右视图
    Leetcode 102. 二叉树的层次遍历
    Leetcode 96. 不同的二叉搜索树
    Leetcode 700. 二叉搜索树中的搜索
    Leetcode 2. Add Two Numbers
    Leetcode 235. Lowest Common Ancestor of a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/staginner/p/2391925.html
Copyright © 2011-2022 走看看