题目大意:中文题~~~~~~~~~~~~~~~~~~
没看出是分组背包,一开始时就觉得像dp,但感觉三个循环可能会超时,没敢写,后来没其他想法了,还是试了一下。首先定义的dp[i][j]就是到第i天时,生气值为j的最少在线时间,那么如果我们知道第i天的生气值为j的最少在线时间b[i][j],那么转移过程就很好转移了,就是dp[i][j+k]=min(dp[i][j],dp[i-1][j]+b[i][k]),意思就是枚举到第i-1天生气值为j的情况,以及第i天生气值为k的情况,那么到第i天生气值为j+k的情况就相应更新。
而b[i][j],怎么处理出来呢,我们先处理个a[i][j]为,第i天前j个小时的生气值的前缀和,然后对于每一天i,我们枚举个上线时间j和下线时间k,这样在线时间就是k-j+1,而在这段时间上线会造成的生气值就是a[i][m]-(a[i][k]-a[i][j-1]),相应地更新就好,详情见代码。
1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 using namespace std; 5 const int inf=0x3f3f3f3f; 6 int dp[250][250],a[250][250],b[250][250]; 7 char s[250]; 8 int main() 9 { 10 int t,n,m,K; 11 scanf("%d",&t); 12 while(t--) 13 { 14 scanf("%d%d%d",&n,&m,&K); 15 for(int i=0;i<=n;i++) 16 for(int j=0;j<=K;j++)//前面值初始化m,wrong了三发 17 dp[i][j]=b[i][j]=inf; 18 for(int i=1;i<=n;i++) 19 { 20 scanf("%s",s+1); 21 for(int j=1;j<=m;j++)//处理前缀和 22 a[i][j]=a[i][j-1]+s[j]-'0'; 23 } 24 int sq; 25 for(int i=1;i<=n;i++) 26 { 27 sq=a[i][m];//当天最多累计的生气值是sq 28 for(int j=sq;j<=K;j++) 29 b[i][j]=0;//那么对于sq及之后的生气值最少上线时间都是0 30 for(int j=1;j<=m;j++)//枚举上线时间 31 for(int k=j;k<=m;k++)//枚举下线时间 32 { 33 sq=a[i][m]-(a[i][k]-a[i][j-1]);//如果在这个时间段下线,当天累计的生气值 34 b[i][sq]=min(b[i][sq],k-j+1); 35 } 36 } 37 dp[0][0]=0; 38 for(int i=1;i<=n;i++) 39 for(int j=0;j<=K;j++)//枚举前i-1天,生气值为j的情况 40 for(int k=0;j+k<=K;k++)//枚举第i天,生气值为k的情况 41 dp[i][j+k]=min(dp[i][j+k],dp[i-1][j]+b[i][k]); //更新前i天,生气值为j+k的情况 42 int ans=inf; 43 for(int i=0;i<=K;i++) 44 ans=min(ans,dp[n][i]); 45 printf("%d\n",ans); 46 } 47 return 0; 48 }
G,E等待更新