洛谷2157 学校食堂(状压DP)
传送门
【题目分析】
用命分析,这个数据范围很状压。。。。。。然后就状压啊。
数组dp[i][j][k]表示前i-1个人已经拿到菜,j枚举i以及他后面7个的拿菜情况,k表示上一个吃饭的位置(相对的)
注意一下枚举的上下界即可。
【代码~】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e3+10;
const int INF=0x3f3f3f3f;
int T;
int n,ans;
int dp[MAXN][1<<9][20];
struct stu{
int x,y;
}st[MAXN];
int Read(){
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
int calc(int a,int b)
{
if(a==0)
return 0;
return st[a].x^st[b].x;
}
void solve()
{
for(int i=1;i<=n+1;i++){
for(int j=0;j<(1<<8);j++){
for(int k=-8;k<=7;k++){
dp[i][j][k+8]=INF;
}
}
}
dp[1][0][7]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<(1<<8);j++){
for(int k=-8;k<=7;k++){
if(dp[i][j][k+8]<INF){
if(j&1)
dp[i+1][j>>1][k+7]=min(dp[i][j][k+8],dp[i+1][j>>1][k+7]);
}
else{
int r=INF;
for(int l=0;l<8;l++){
if(!(j&(1<<l))){
if(i+l>r)
break;
r=min(r,i+l+st[i+l].y);
dp[i][j+(1<<l)][l+8]=min(dp[i][j+(1<<l)][l+8],dp[i][j][k+8]+calc(i+k,i+l));
}
}
}
}
}
}
}
int main()
{
T=Read();
while(T--)
{
n=Read();
for(int i=1;i<=n;i++)
st[i].x=Read(),st[i].y=Read();
solve();
ans=INF;
for(int i=-8;i<0;i++)
ans=min(dp[n+1][0][i+8],ans);
cout<<ans<<'\n';
}
return 0;
}