1. 程式人生 > >Codeforces 946D Timetable(預處理+分組背包)

Codeforces 946D Timetable(預處理+分組背包)

鏈接 pre AI 分組背包 std inf time pro can

題目鏈接:http://codeforces.com/problemset/problem/946/D

題目大意:有n個字符串,代表n天的課表,1表示這個時間要上課,0表示不要上課,一天在學校時間為第一節課到最後一節課的時間。總共,可以逃過k次課,求至少需要在學校多少時間。

解題思路:聽了大佬說背包,然後預處理就想了20多分鐘,比賽結束,GG。。。先是預處理出v[i][k]即第i天逃k節課的能節約的最多時間,至於怎麽求,直接枚舉k,然後枚舉兩端1的位置即可。然後就可以做分組背包了,這就不說了,很簡單。

代碼

 1 #include<iostream>
 2 #include<cstdio>
 3
#include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long LL; 7 const int N=1e3+5; 8 const int INF=0x3f3f3f3f; 9 10 char s[N][N]; 11 int num[N],pos[N][N],dp[N],v[N][N]; //pos[i][j]對應第i個字符串第j個‘1‘的位置,num[i]記錄第i個字符串‘1‘的數量 12 //
v[i][k]即第i段字符串刪除k個1節約的時間 13 int main(){ 14 int n,m,lim; 15 scanf("%d%d%d",&n,&m,&lim); 16 for(int i=0;i<n;i++){ 17 scanf("%s",s[i]); 18 for(int j=0;j<m;j++){ 19 if(s[i][j]==1){ 20 num[i]++; 21 pos[i][num[i]]=j;
22 } 23 } 24 } 25 //處理出v[i][k], 26 for(int i=0;i<n;i++){ 27 int cnt=0; 28 //枚舉k 29 for(int k=0;k<=min(num[i]-1,lim);k++){ 30 int res=INF; 31 //左進p個1,右進q個1 32 for(int p=0;p<=k;p++){ 33 int q=(k-p); 34 res=min(res,pos[i][num[i]-q]-pos[i][p+1]+1); 35 } 36 v[i][k]=m-res; 37 } 38 v[i][num[i]]=m; 39 } 40 //分組背包 41 memset(dp,0,sizeof(dp)); 42 for(int i=0;i<n;i++){ 43 for(int j=lim;j>=0;j--){ 44 for(int k=0;k<=min(j,m);k++){ 45 dp[j]=max(dp[j],dp[j-k]+v[i][k]); 46 } 47 } 48 } 49 printf("%d\n",m*n-dp[lim]); 50 return 0; 51 }

Codeforces 946D Timetable(預處理+分組背包)