題目鏈接
大意:n個人,選k個觀衆,p個球員,每個人當觀衆的能力爲,在每個位置的能力爲,讓你選擇個人使得能力和最大。
思路:考慮狀壓,表示到第個人時的第個狀態的最大能力,狀態表示每個位置被選與否。
那麼轉移時只需要考慮兩個地方:
1.前個人是否選滿了個觀衆
2.在狀態下還有哪個位置沒人上
觀察第一個地方,我們要使得我們選的觀衆能力和是當前狀態下最大的,那麼我們需要將所有人按照非遞增順序排列才能滿足這一點,那麼選的聽衆肯定就是能選的人中能力值最大的。
注意所有轉移都要從合法情況轉移得到。
初始只有合法。
細節見代碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
int n,p,k,a[N],s[N][8],d[N],vis[N];
LL f[N][128];
LL sum=0;
int main() {
ios::sync_with_stdio(false);
cin>>n>>p>>k;
for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i],d[i]=i;
for(int i=1;i<=n;i++){
for(int j=1;j<=p;j++){
cin>>s[i][j];
}
}
memset(f,-1,sizeof f);
f[0][0]=0;//初始
sort(d+1,d+1+n,[](int x,int y){
return a[x]>a[y];//排序
});
for(int i=1;i<=n;i++){
for(int j=0;j<(1<<p);j++){
int tmp=0;
for(int q=0;q<p;q++){
if((1<<q)&j)tmp++;
}
if(i-1-tmp>=k&&f[i-1][j]!=-1)f[i][j]=f[i-1][j];//選滿了
else if(i-1-tmp<k&&f[i-1][j]!=-1)f[i][j]=f[i-1][j]+a[d[i]];//沒選滿
}
for(int j=0;j<(1<<p);j++){
for(int q=0;q<p;q++){
if(!((1<<q)&j) && f[i-1][j]!=-1){
f[i][j|(1<<q)]=max(f[i][j|(1<<q)],f[i-1][j]+s[d[i]][q+1]);//q這個位置還缺人
}
}
}
}
cout<<f[n][(1<<p)-1]<<'\n';
return 0;
}