題意是一排路燈,每個路燈有耗電量,照明度,需要給這n個路燈按順序分組,每組內的最大耗電量是電燈數乘t,可以選擇關閉一些電燈,求最大的照明度;
這題思路很明顯,預處理出一個g[i][j]表示i到j分為一組的最大照明度,f[i][j]表示前i個分為j組的最大照明度,f[i][j]=max(f[k-1][j-1]+f[k][i]);
樸素的預處理是這麼搞的
int h[maxm*maxn];
for(int i=;i<=n;i++)
for(int j=i;j<=n;j++){
memset(h,,sizeof(h));
int s=(j-i+)*t;
for(int k=i;k<=j;k++)
for(int c=s;c>=;c--){
if(c<w[k])break;
h[c]=max(h[c],h[c-w[k]]+v[k]);
}
g[i][j]=g[j][i]=h[s];
}
n^4,無法接受,觀察了一下,發現h陣列每次都這麼清一遍太浪費了,要想想怎麼從前面的h中獲取資訊,發現每次h中有i-j的最優資訊,然後處理i-j+1的時候相當於又處理了一遍i-j,要找i-j+1的g值,可以考慮一下不清空h陣列,直接從j+1向上搞,但是每次最大耗電量都不一樣,直接可以設成i-n的最大耗電,然後每次處理完後,在1-當前最大耗電裡找最大值就行了,省了一維,可以通過了;
修改程式碼:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
using namespace std;
const int maxn=,maxm=;
int n,m,t,w[maxn],v[maxn];
int g[maxn][maxn],f[maxn][maxm];
void init(){
scanf("%d%d%d",&n,&m,&t);
for(int i=;i<=n;i++)scanf("%d%d",&w[i],&v[i]);
int h[maxn*maxn];
for(int i=;i<=n;i++){
memset(h,,sizeof(h));
int s=(n-i+)*t;
for(int j=i;j<=n;j++){
int S=(j-i+)*t;
for(int c=s;c>=;c--){
if(c<w[j])break;
h[c]=max(h[c],h[c-w[j]]+v[j]);
}
g[i][j]=g[j][i]=h[S];
}
}
}
void work(){
for(int i=;i<=n;i++)
for(int k=;k<=m&&k<=i;k++){
for(int j=k;j<=i;j++){
f[i][k]=max(f[i][k],f[j-][k-]+g[j][i]);
}
}
cout<<f[n][m]<<endl;
}
int main(){
init();
work();
}