• UVA-10163 Storage Keepers DP


    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1104

    题意:

      有n个仓库(最多100个),m个管理员(最多30个),每个管理员有一个能力值P(接下来的一行有m个数,表示每个管理员的能力值).每个仓库只能由一个管理员看管,但是每个管理员可以看管k个仓库(但是这个仓库分配到的安全值只有p/k,其中p/k取整数部分), 每个月公司都要给看管员工资,雇用的管理员的工资即为他们的能力值p和,问,使每个仓库的安全值最高的前提下,使的工资总和最小。

    输出最大安全值,并且输出最少的花费。

    题解:

      令dp[i][j]==x表示前i个人看管j个仓库时, 能获得的最大安全总值为x.  或者你也可以二分求解

      第二次DP过程, 求在最大安全总值==L的情况下, 总花费最小.

           令dp[i][j]==x表示前i个人看管j个仓库且最大安全总值==L时, 最小花费为x.

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define ls i<<1
    #define rs ls | 1
    #define mid ((ll+rr)>>1)
    #define pii pair<int,int>
    #define MP make_pair
    typedef long long LL;
    const long long INF = 1e17+1LL;
    const double Pi = acos(-1.0);
    const int N = 200+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10;
    
    
    int dp1[N][N],dp2[N][N],n,m,p[N];
    void solve() {
        for(int i = 0; i <= m; ++i)
            for(int j = 0; j <= n; ++j) dp1[i][j] = inf;
        for(int i = 1; i <= m; ++i) {
            for(int j = 1; j <= n; ++j) {
                dp1[i][j] = dp1[i-1][j];
                if(i == 1) dp1[i][j] = p[i] / j;
                else  dp1[i][j] = dp1[i-1][j];
                for(int k = 0; k < j; ++k) {
                    if(i!=1)dp1[i][j] = max(dp1[i][j],min(dp1[i-1][k],p[i]/(j-k)));
                }
            }
        }
    
        for(int i = 0; i <= m; ++i)
            for(int j = 0; j <= n; ++j) dp2[i][j] = 0;
        for(int i = 1; i <= m; ++i) {
            for(int j = 1; j <= n; ++j) {
                if(i == 1) dp2[i][j] = (p[i]/j)>=dp1[m][n]?p[i]:inf;
                else dp2[i][j] = dp2[i-1][j];
                if(i != 1)
                for(int k = 0; k < j; ++k) {
                    if(p[i] / (j-k) >= dp1[m][n])
                        dp2[i][j] = min(dp2[i][j],dp2[i-1][k]+p[i]);
                }
            }
        }
        if(dp1[m][n] == 0) cout<<"0 0"<<endl;else
        cout<<dp1[m][n]<<" "<<dp2[m][n]<<endl;
    }
    int main() {
        while(scanf("%d%d",&n,&m)!=EOF) {
            if(n == 0 && m == 0) break;
            for(int i = 1; i <= m; ++i) scanf("%d",&p[i]);
            solve();
        }
        return 0;
    }
  • 相关阅读:
    mysql explain用法和结果的含义
    heapset水平自动扩容
    dashboard安装
    对List集合中的对象进行按某个属性排序
    MySql查询当天、本周、本月、本季度、本年的数据
    三种List集合的遍历方式
    Date相关处理
    ubuntu-14.04.2-desktop使用方法
    PowerShell命令卸载Win10内置应用
    Windows下MySQL绿色版安装配置与使用
  • 原文地址:https://www.cnblogs.com/zxhl/p/6506222.html
Copyright © 2020-2023  润新知