因为每个人的B值不超过7,所以上一个吃饭的人应该在这个人前面不超过7,后面也不超过7的位置上
状压DP,设f[i][j][k]为前i-1个人都已经吃完饭了,第i到i+7个人的状态为j,最后一个吃饭的人为第i+k个人
然后就可以转移
对于j&1==1,就是说第i个人已经吃了饭了,那么f[i+1][j>>1][k-1]=f[i][j][k],两者的意义是一样的
对于j&1==0,那么就枚举应当作为最后一个吃饭的人的位置i+p,f[i][j^(1<<p)][p]=f[i][j][k]+cal(i+k,i+p))
然后因为k有可能为负,所以整体的k+8存入数组
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int T[1100],B[1100]; int f[1100][310][21]; int cal(int x,int y){return (x==0||y==0)?0:T[x]^T[y];} int main() { int cas; scanf("%d",&cas); while(cas--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&T[i],&B[i]); memset(f,63,sizeof(f)); f[1][0][7]=0; for(int i=1;i<=n;i++) { for(int j=0;j<(1<<8);j++) { for(int k=0;k<=15;k++) { if(f[i][j][k]==f[0][0][0]) continue; if(j&1) f[i+1][j>>1][k-1]=min(f[i+1][j>>1][k-1],f[i][j][k]); else { int mmax=1<<30; for(int p=0;p<=7;p++) { if((j&(1<<p))==0) { if(i+p>mmax) break; mmax=min(mmax,i+p+B[i+p]); f[i][j^(1<<p)][p+8]=min(f[i][j^(1<<p)][p+8],f[i][j][k]+cal(i+k-8,i+p)); } } } } } } int ans=1<<30; for(int k=0;k<=8;k++) ans=min(f[n+1][0][k],ans); printf("%d\n",ans); } return 0; }
原文:https://www.cnblogs.com/Never-mind/p/10323034.html