题目链接
题目大意:
总共有n个人,每个人可以当做观众或者球员,每个位置只有一个球员,给定每个人当观众的价值和每个人在每个位置的价值。其中共有p(p<=7)个球员和k个观众,求出怎么安排使得总价值最大。
解题思路:
首先贪心一下,把他们按观众价值从大到小排序,所以在观众人数还没满的情况下如果不当球员就一定会当观众。然后进行状压dp,状态为dp[i][sta],表示第i个人,其中状态sta上二进制为1的地方表示这个位置已经有球员了。
所以状态转移为:
首先:dp[i][sta] = dp[i-1][sta]继承上一个人的状态
当观众:
观众还有余量的时候
if (i-cal_num(sta)<=k)
dp[i][sta]=max(dp[i][sta],dp[i-1][sta]+a[i].a);
当球员:
踢第j个位置,则这个状态必须在第j个有球员。
if(sta
⊕
\oplus
⊕(1<<j)==1),
dp[i][sta]=max(dp[i][sta],dp[i-1][sta
⊕
\oplus
⊕ (1<<j)]+people.p[j]),
解题代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll inf=1e18;
struct P
{
ll a,s[7];
friend bool operator<(P t1,P t2)
{
return t1.a>t2.a;
}
}a[maxn];
ll dp[maxn][1<<8];
int cal_num(int sta)
{
int ret=0;
while (sta)
{
if (sta&1)
ret++;
sta>>=1;
}
return ret;
}
int main()
{
ll n,p,k;
scanf("%I64d%I64d%I64d",&n,&p,&k);
for (int i=1;i<=n;i++)
scanf("%I64d",&a[i].a);
for (int i=1;i<=n;i++)
{
for (int j=0;j<p;j++)
scanf("%I64d",&a[i].s[j]);
}
sort(a+1,a+1+n);
//不要忘记初始化
for(int sta=0;sta<(1<<p);sta++)
dp[0][sta]=-inf;
dp[0][0]=0;
for (int i=1;i<=n;i++)
{
for (int sta=0;sta<(1<<p);sta++)
{
dp[i][sta]=dp[i-1][sta];
if (i-cal_num(sta)<=k)
dp[i][sta]=max(dp[i][sta],dp[i-1][sta]+a[i].a);
for (int j=0;j<p;j++)
{
if ((1<<j)&sta)
{
dp[i][sta]=max(dp[i][sta],dp[i-1][sta^(1<<j)]+a[i].s[j]);
}
}
}
}
cout<<dp[n][(1<<p)-1];
}