首页 > 代码库 > JZOJ 1312:关灯问题

JZOJ 1312:关灯问题

传送门

少见的DP再DP题目。题面不短,但是可以看出来这是一道DP题。而且正解的算法复杂度应该是$O(N^3)$。而且给了部分$O(N^4)$的算法的分。可以看出来要AC是要在DP上加上优化的。

设$g[i][j]$表示$[i,j]$内满足条件的最大答案贡献,这个用背包可以很轻松的处理出来。然后再设$f[i][k]$表示前$i$个分$k$组的最大答案。可以得到如下状态转移

$f[i][k]=max\{ f[j-1][k-1]+g[j][i] \}$

把背包上的枚举优化掉一维就行了。

代码实现上也存在诸多细节。

技术分享
 1 //OJ 1312 2 //by Cydiater 3 //2016.10.6 4 #include <iostream> 5 #include <cstring> 6 #include <string> 7 #include <algorithm> 8 #include <queue> 9 #include <map>10 #include <ctime>11 #include <iomanip>12 #include <cstdlib>13 #include <cstdio>14 #include <cmath>15 using namespace std;16 #define ll long long17 #define up(i,j,n)        for(int i=j;i<=n;i++)18 #define down(i,j,n)        for(int i=j;i>=n;i--)19 #define pii pair<int,int>20 #define fi first21 #define se second22 const int MAXN=1e3+5;23 const int oo=0x3f3f3f3f;24 inline int read(){25     char ch=getchar();int x=0,f=1;26     while(ch>9||ch<0){if(ch==-)f=-1;ch=getchar();}27     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}28     return x*f;29 }30 int N,M,T,g[MAXN][MAXN],pack[MAXN*MAXN],f[MAXN][MAXN];31 pii light[MAXN*MAXN];32 namespace solution{33     void init(){34         N=read();M=read();T=read();35         up(i,1,N){36             int x=read(),y=read();37             light[i]=make_pair(x,y);38         }39     }40     void pret(){41         memset(g,0,sizeof(g));42         up(i,1,N){43             memset(pack,0,sizeof(pack));44             up(j,i,N){45                 down(k,(N-i+1)*T,light[j].fi)pack[k]=max(max(pack[k],pack[k-1]),pack[k-light[j].fi]+light[j].se);46                 g[i][j]=g[j][i]=pack[(j-i+1)*T];47             }48         }49     }50     void DP(){51         memset(f,0,sizeof(f));52         up(i,1,N)up(k,1,min(M,i))up(j,k,i)f[i][k]=max(f[i][k],f[j-1][k-1]+g[j][i]);53         cout<<f[N][M]<<endl;54     }55 }56 int main(){57     //freopen("input.in","r",stdin);58     using namespace solution;59     init();60     pret();61     DP();62     return 0;63 }
View Code

 

JZOJ 1312:关灯问题