習題: Team Building(狀壓DP)
阿新 • • 發佈:2020-08-09
題目
思路
首先有一個性質,如果我們已經確定了哪些人作為隊員,那麼其餘的觀眾一定是貪心地從大到小的去選
首先將人按他們在觀眾上能提供的貢獻進行排序
設\(dp[i][j]\)為前i個人,排球隊員的狀態為j
再有一個性質,如果我們設j中為cnt個1,
如果i>cnt+k,那麼第i個人一定不會被選為觀眾(這應該很好理解吧)
也就是指只有在\(i<=cnt+k\)的時候,我們才考慮i這個人作為觀眾的貢獻,
如果是i這個人作為排球隊員,直接暴力轉移即可
程式碼
#include<iostream> #include<algorithm> #include<cstring> using namespace std; int n,p,k; long long dp[100005][(1<<8)]; struct node { long long val; long long s[8]; friend bool operator < (const node &a,const node &b) { return a.val>b.val; } }a[100005]; int calc(int val) { int ret=0; while(val) { ret=ret+(val&1); val>>=1; } return ret; } int main() { ios::sync_with_stdio(false); cin>>n>>p>>k; for(int i=1;i<=n;i++) cin>>a[i].val; for(int i=1;i<=n;i++) for(int j=0;j<p;j++) cin>>a[i].s[j]; sort(a+1,a+n+1); memset(dp,-0x3f,sizeof(dp)); dp[0][0]=0; for(int i=1;i<=n;i++) { for(int j=0;j<(1<<p);j++) { dp[i][j]=max(dp[i][j],dp[i-1][j]); if(i<=calc(j)+k) dp[i][j]=max(dp[i][j],dp[i-1][j]+a[i].val); for(int t=0;(1<<t)<(1<<p);t++) { if((j&(1<<t))==0) { dp[i][j|(1<<t)]=max(dp[i][j|(1<<t)],dp[i-1][j]+a[i].s[t]); } } } } cout<<dp[n][(1<<p)-1]; return 0; }