题目链接:http://hihocoder.com/problemset/problem/1137
题意:有N个员工来面试,已知每个人的价值和薪水,公式收人的要求是:1.要x男y女,2.这x+y个员工的总薪水不能超过B,3.在前两点的前提上要是要使总价值最大,基于此还要使总薪水最小。4.如果答案不唯一,选择员工编号的字典序最小的方案。
要求输出选择员工的总价值和总薪水,并且输出他们的编号。
解析:本来看到总共就100的数据,就去深搜,结果超时很多,看到题解是背包的题目,感觉是很好的题目,希望以后遇到这种题能A出来,下面题解讲的很好,题解:hiho一下第83周《Recruitment》题目分析
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define M 105
int n,x,y,b;
struct node{
int v,s,id;
}mlist[M],flist[M];
int totv,tots,mp[1005],fp[1005];//p[v]表示总薪水不超过v时,获得最大价值的总薪水值。
int maleNum,femaleNum;
int mf[M][M][1005]; //表示前i个男员工中选择j个,总薪水恰好为k的价值。若不存在合法方案,价值为0。
int ff[M][M][1005]; //表示前i个女员工中选择j个,总薪水恰好为k的价值。若不存在合法方案,价值为0。
int mg[M][M][1005]; //若mf[i][j][k]存在合法方案,则g[i][j][k]表示该方案中最后选取的员工序号,否则为-1。
int fg[M][M][1005]; //若ff[i][j][k]存在合法方案,则g[i][j][k]表示该方案中最后选取的员工序号,否则为-1。
vector<int>ans;
int main()
{
int i,j,k;
char op;
scanf("%d%d%d%d",&n,&x,&y,&b);
maleNum=femaleNum=0;
getchar();
for(i=1;i<=n;i++)
{
scanf("%c%d%d",&op,&j,&k);
if(op=='M')
{
maleNum++;
mlist[maleNum].id=i;
mlist[maleNum].v=j;
mlist[maleNum].s=k;
}else{
femaleNum++;
flist[femaleNum].id=i;
flist[femaleNum].v=j;
flist[femaleNum].s=k;
}
getchar();
}
//先处理男方
memset(mf,0,sizeof(mf));
memset(mg,-1,sizeof(mg));
mg[0][0][0]=0;
//dp求mf数组
for(i=1;i<=maleNum;i++)
{
for(j=0;j<=x;j++)
{
for(k=0;k<=b;k++)
{
mf[i][j][k]=mf[i-1][j][k];
mg[i][j][k]=mg[i-1][j][k];
if(j>0&&k>=mlist[i].s&&mg[i-1][j-1][k-mlist[i].s]!=-1&&mf[i][j][k]<mf[i-1][j-1][k-mlist[i].s]+mlist[i].v)
{
mf[i][j][k]=mf[i-1][j-1][k-mlist[i].s]+mlist[i].v;
mg[i][j][k]=i;
}
}
}
}
//将B的总薪水分配给男女两边时
//计算男方总薪水不超过i时,获得最大价值的总薪水值。
memset(mp,-1,sizeof(mp));
for(i=0;i<=b;i++)
{
if(i>0)
mp[i]=mp[i-1];
if(mg[maleNum][x][i]!=-1)
{
if(mp[i]==-1)
{
mp[i]=i;
}
else
{
if(mf[maleNum][x][i]>mf[maleNum][x][mp[i]])
{
mp[i]=i;
}
}
}
}
//处理女方
memset(ff,0,sizeof(ff));
memset(fg,-1,sizeof(fg));
fg[0][0][0]=0;
//dp求ff数组
for(i=1;i<=femaleNum;i++)
{
for(j=0;j<=y;j++)
{
for(k=0;k<=b;k++)
{
ff[i][j][k]=ff[i-1][j][k];
fg[i][j][k]=fg[i-1][j][k];
if(j>0&&k>=flist[i].s&&fg[i-1][j-1][k-flist[i].s]!=-1&&ff[i][j][k]<ff[i-1][j-1][k-flist[i].s]+flist[i].v)
{
ff[i][j][k]=ff[i-1][j-1][k-flist[i].s]+flist[i].v;
fg[i][j][k]=i;
}
}
}
}
//将B的总薪水分配给男女两边时
//计算女方总薪水不超过i时,获得最大价值的总薪水值。
memset(fp,-1,sizeof(fp));
for(i=0;i<=b;i++)
{
if(i>0)
fp[i]=fp[i-1];
if(fg[femaleNum][y][i]!=-1)
{
if(fp[i]==-1)
{
fp[i]=i;
}
else
{
if(ff[femaleNum][y][i]>ff[femaleNum][y][fp[i]])
{
fp[i]=i;
}
}
}
}
//计算怎么将总薪水b分配给男女两边
tots=totv=0;
for(i=0;i<=b;i++)
{
if(mp[i]!=-1&&fp[b-i]!=-1&&totv<mf[maleNum][x][mp[i]]+ff[femaleNum][y][fp[b-i]])
{
totv=mf[maleNum][x][mp[i]]+ff[femaleNum][y][fp[b-i]];//totv即是最大总价值
tots=i; //mp[tots]是给男方的总薪水
}
}
//利用g数组,当给定一方总薪水时,可以求解出对应总薪水的合法方案。
//男方选中人员
i=maleNum; j=x; k=mp[tots];
while(j>0)
{
i=mg[i][j][k];
ans.push_back(mlist[i].id);
j=j-1;
k=k-mlist[i].s;
i=i-1;
}
//女方选中人员
i=femaleNum; j=y; k=fp[b-tots];
while(j>0)
{
i=fg[i][j][k];
ans.push_back(flist[i].id);
j=j-1;
k=k-flist[i].s;
i=i-1;
}
printf("%d %d\n",totv,mp[tots]+fp[b-tots]);
sort(ans.begin(),ans.end());
vector<int>::iterator it;
for(it=ans.begin();it!=ans.end();it++)
{
printf("%d ",*it);
}
printf("\n");
return 0;
}
超时深搜:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define M 105
int n,x,y,b;
struct node{
char g;
int v,s;
}a[M];
int totV,totS;
bool vis[M],temp[M];
void dfs(int it,int m,int f,int tv,int ts)// 该考虑it号应聘者,已经选了m男,f女,总能力值为tv,总工资为s
{
if(ts>b||m>x||f>y)
return;
if(m==x&&f==y)
{
if(tv>totV)
{
totV=tv;
totS=ts;
for(int i=1;i<=n;i++)
vis[i]=temp[i];
}
return;
}
for(int i=it;i<=n;i++)
{
if(a[i].s>b)
continue;
if(a[i].g=='M')
{
if(m<x)
{
temp[i]=true;
dfs(i+1,m+1,f,tv+a[i].v,ts+a[i].s);
temp[i]=false;
dfs(i+1,m,f,tv,ts);
}
}else{
if(f<y)
{
temp[i]=true;
dfs(i+1,m,f+1,tv+a[i].v,ts+a[i].s);
temp[i]=false;
dfs(i+1,m,f,tv,ts);
}
}
}
}
int main()
{
int i,j;
scanf("%d%d%d%d",&n,&x,&y,&b);
getchar();
for(i=1;i<=n;i++)
{
scanf("%c%d%d",&a[i].g,&a[i].v,&a[i].s);
getchar();
}
totV=totS=0;
memset(vis,false,sizeof(vis));
memset(temp,false,sizeof(temp));
dfs(1,0,0,0,0);
printf("%d %d\n",totV,totS);
for(j=1;j<=n;j++)
{
if(vis[j])
printf("%d ",j);
}
printf("\n");
return 0;
}