hdu 1684 dp

本文介绍了一个使用动态规划解决工程项目利润最大化的问题。问题涉及多个工程、人员雇佣数量、完成概率及奖惩制度,通过构建状态转移方程实现了最优解的求解。

http://acm.hdu.edu.cn/showproblem.php?pid=1684

题意:有m个工程,最多可以雇佣n个人,已知概率pij表示完成第i个工程雇佣j个人时,能按时完成的概率,同时,已知完成一个工程的奖金和无法完成时的罚款,还有每一个人的工资,当然,如果参与的工程无法按时完成,则参与的人不需要支付工资。求这m个工程的最大利润,同时求出需要的人数,多种方案时,从小到大输出人数。

状态转移方程:
dp[i][j]表示到第i个工程,雇佣j个人的最大利润
dp[i][j]=max(dp[i-1][j-k]+pik *(reward-k*salary)-(100-pik)*punish k表示当前工程雇佣的人数

做题过程:

        根据解题思路写了代码,感觉自己初始化应该对的。但是还是WA了两次,有待找出原因。

        哎,还是初始化的原因:1.不做项目的时候,下一个的期望必须加上上一个的期望。   2.上式中dp[i][j]不是找个最大吗? 它自己应该最先赋值为无穷小。  我还把dp改成__int64了呢。。。。

/*
Pro: 0

Sol:

date:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#define inf 1100000000
#define maxn 101
using namespace std;
int proj_num,peo_num,t,salary;
int p[maxn][maxn],punish[maxn],reward[maxn];
__int64 dp[maxn][maxn];
int main(){
    scanf("%d",&t);
    while(t --){
        memset(dp,0,sizeof(dp));
        scanf("%d%d%d",&proj_num, &peo_num,&salary);
        for(int i = 1; i <= proj_num; i ++){
            for(int j = 1; j <= peo_num; j ++){
                scanf("%d",&p[i][j]);
            }
            scanf("%d%d",&reward[i],&punish[i]);
        }
        //初始化
        dp[0][0] = 0;
        for(int pro = 1; pro <= proj_num; pro ++){
            dp[pro][0] = dp[pro - 1][0]- punish[pro] * 100;//这里下一个要加上上一个!!!
        }
        for(int peo = 1; peo <= peo_num; peo ++){
            dp[1][peo] = p[1][peo] * (reward[1] - salary * peo) - (100 - p[1][peo]) * punish[1];
        }
        //开始dp了
        for(int pro = 2; pro <= proj_num; pro ++){
            for(int tpeo = 0; tpeo <= peo_num; tpeo ++){
                dp[pro][tpeo] = -inf; //这里赋值为无穷小
                for(int npeo = 0; npeo <= tpeo; npeo ++){
                    dp[pro][tpeo] = max(dp[pro][tpeo], dp[pro - 1][tpeo - npeo] + p[pro][npeo] * (reward[pro] - salary * npeo) - punish[pro] * (100 - p[pro][npeo]));
                }
            }
        }
        __int64 Max = -inf;
        int sub = 0,ans[maxn];
        for(int peo = 0; peo <= peo_num; peo ++){
            if(Max < dp[proj_num][peo])
                Max = dp[proj_num][peo];
        }
        for(int peo = 0; peo <= peo_num; peo ++){
            if(dp[proj_num][peo] == Max){
                ans[sub ++] = peo;
            }
        }
        printf("%I64d\n",Max);
        for(int i = 0; i < sub - 1; i ++)
            printf("%d ",ans[i]);   printf("%d\n",ans[sub - 1]);
    }
	return 0;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值