標籤:lin inf pac lse bre reg -- else col
f[i][j][k]分別代表1-i-1個人全部打完飯時i及其後7個人的狀態為j時最後一個打飯的人為i+k的狀態下所用的最小時間
當i已經打過飯時 即 j&1 那麼 f [i] [j>>1] [k+1] =min(~, f[i] [j] [k]);
如果沒有那麼枚舉其後的打飯的人同時注意要保證忍耐度的條件,所以利用r找i+h+b[i+h]的最小值,也就是i所能選取的最遠邊界
如果當前迴圈的h已經超過範圍r 那麼結束此次更新答案
否則 f[i] [j|(1<<h)] [h] =min(~ , f[i][j][k] + i+k?(t[i+k]^t[i+h]):0)
最終在n+1,處代表前n已經打完飯,j=0代表後面的狀態不再選取,k由-8到-1的全部情況
#include<bits/stdc++.h>#define rep(i,x,y) for(register int i=x;i<=y;i++)using namespace std;inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;}const int N=1050;const int inf=0x3f3f3f3f;int n,t[N],b[N],dp[N][1<<8][20];#define f(i,j,k) dp[i][j][k+8]inline void sudo(){ n=read(); rep(i,1,n) t[i]=read(),b[i]=read(); memset(dp,inf,sizeof dp); f(1,0,-1)=0; rep(i,1,n)rep(j,0,(1<<8)-1) rep(k,-8,7)if(f(i,j,k)!=inf) if(j&1) f(i+1,j>>1,k-1)=min(f(i+1,j>>1,k-1),f(i,j,k)); else{ int r=inf; rep(h,0,7)if(!((j>>h)&1)){//在這個人之前的未打飯的人 if(i+h>r) break; r=min(r,i+h+b[i+h]); //距離i的最遠距離 //判斷i+k就是判斷上一次是否是起點 f(i,j|(1<<h),h)=min(f(i,j|(1<<h),h),f(i,j,k)+(i+k?(t[i+k]^t[i+h]):0)); } } int ans=inf; rep(k,-8,-1) ans=min(ans,f(n+1,0,k)); printf("%d\n",ans);return;}int main(){ int T=read();while(T--) sudo();return 0;}
完結撒花
luogu 2157 狀壓dp