题意:有m个工程,最多可以雇佣n个人,已知概率pij表示完成第i个工程雇佣j个人时,能按时完成的概率,同时,已知完成一个工程的奖金和无法完成时的罚款,还有每一个人的工资,当然,如果参与的工程无法按时完成,则参与的人不需要支付工资。求这m个工程的最大利润,同时求出需要的人数,多种方案时,从小到大输出人数。
分析:想了想,应该还是一道DP,当这么想的时候,很快就写出了状态转移方程,不过却被一些细节拌住了,调了N久,WA了n次
状态转移方程:
dp[i][j]表示到第i个工程,雇佣j个人的最大利润
dp[i][j]=max(dp[i-1][j-k]+pik *(reward-k*salary)-(100-pik)*punish k表示当前工程雇佣的人数
当然,还有很多需要注意的地方,初始化问题
View Code
#include<iostream>
#include<algorithm>
using namespace std;
int dp[101][101];
int n,m,sal;
struct pro
{
int p[101],pun,rew;
}pr[101];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&m,&n,&sal);
for(int i=1;i<=m;i++)
{
pr[i].p[0]=0;
for(int j=1;j<=n;j++)
scanf("%d",&pr[i].p[j]);
scanf("%d %d",&pr[i].rew,&pr[i].pun);
}
memset(dp,0,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=m;i++)
dp[i][0]=dp[i-1][0]-pr[i].pun*100;
for(int i=1;i<=n;i++)//第一个工程要单独处理,放到下面的循环的话,出现了很大一个问题,就是第一个工程前面没有工程了,所以雇佣人数上面是自由的,这里WA了一次
dp[1][i]=(pr[1].rew-sal*i)*pr[1].p[i]-(100-pr[1].p[i])*pr[1].pun;
for(int i=2;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=-INT_MAX;//这里WA了一次,一开始居然赋值为0,太滑稽了
for(int k=0;k<=j;k++)
{
int temp=dp[i-1][j-k]+(pr[i].rew-sal*k)*pr[i].p[k]-(100-pr[i].p[k])*pr[i].pun;
if(temp>dp[i][j])
dp[i][j]=temp;
}
}
}
int max1=-INT_MAX;
for(int i=0;i<=n;i++)//从0开始循环,这里也WA了一次,因为N有可能等于0,
{
if(dp[m][i]>max1)
max1=dp[m][i];
}
printf("%d\n",max1);
int flag=1;
for(int i=0;i<=n;i++)//这里也是,……
{
if(max1==dp[m][i])
{
if(flag)
{
printf("%d",i);
flag=0;
}
else printf(" %d",i);
}
}
printf("\n");
}
return 0;
}