http://hihocoder.com/problemset/problem/1044
可以看出来每一位的选取只与前m位有关,我们把每个位置起始的前m位选取状态看出01序列,就可以作为一个数字来存储,那么将其作为状态,dp[i][j]就是第i个座位前m个座位选取情况为j的最大垃圾处理量。然后取这个序列的后m-1位,和当前位取0/1的情况分别做合法性判断,然后做状态转移即可。
#include <iostream> using namespace std; const int N=1005; const int inf=99999999; int dp[N][2000]; int n,m,q; int w[N]; int cntb(int num) { int c=0; while(num) c+=num%2,num>>=1; return c; } int main() { cin.sync_with_stdio(false); while(cin>>n>>m>>q) { for(int i=1; i<=n; i++) cin>>w[i]; for(int i=0; i<(1<<m); i++) dp[0][i]=-inf; dp[0][0]=0; int d=1<<(m-1); for(int i=1; i<=n; i++) { for(int j=0;j<(1<<m);j++) dp[i][j]=-inf; for(int j=0;j<(1<<m);j++) { int qc=cntb(j>>1); if(qc>q)continue; if(qc==q)dp[i][j>>1]=max(dp[i][j>>1],dp[i-1][j]); else { dp[i][d+(j>>1)]=max(dp[i][d+(j>>1)],dp[i-1][j]+w[i]); dp[i][j>>1]=max(dp[i][j>>1],dp[i-1][j]); } } } int ans=-inf; for(int i=0;i<(1<<m);i++) ans=max(dp[n][i],ans); cout<<ans<<endl; } return 0; }