P2157 [SDOI2009]学校食堂

我的这个方法比较奇怪,我是用队列来实现转移的。

首先分析一下题目性质。如果(x)是打完饭的人当中排队最靠后的,那么1到x-8这些人肯定都打完饭了。定义状态(f_{i,j,k})表示标号最大的打到饭的是(i)(有点拗口),最后一个打饭的是(i-k)(k)的范围是0到7,(i-1)(i-7)的状态是(j),需要的最少的时间。

这种状态定义没有后效性(想想为什么),只是不好确定转移的顺序。核心操作来了,其实说白了就是bfs,我们可以用队列存状态,每次取队首向外一层一层的扩展。这种方法还附带剪枝的功能,跑的飞快。

代码实现比较繁琐,注意要把不合法的状态及时排除掉。

update 好像我的状态和转移都是是一样的,别的题解直接利用拓扑序转移的。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define forg(i,x) for(int i=first[x];i;i=nxt[i])
#define uu unsigned
#define fi first
#define se second
#define od(x) ((x)&1)
#define ev(x) (od(x)^1)
#define mi2(x) (1<<(x))
#define gw(x,j) ((x)>>(j)&1)
//取出二进制数的某一位
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)

const int inf=0x3f3f3f3f;
int n,t[1003],b[1003],dp[1003][8][1<<7],lim;
int nn;
struct dul{
	int a,b,c;
}q[2000003];
inline bool vad1(int i,int zi,int k){
	//if(b[i-k]<k)return 0;
	for(int ii=k+1;ii<=7;++ii)if(!gw(zi,ii-1)&&b[i-ii]<ii-k)return 0;
	return 1;
}
inline bool vad2(int i,int zi,int k){
	if(i+k>n)return 0;
	for(int ii=1;ii<=7;++ii)if(!gw(zi,ii-1)&&b[i-ii]<k+ii)return 0;
	for(int ii=1;ii<k;++ii)if(b[i+ii]<k-ii)return 0;
	return 1;
}
inline void pr2(int zi){for(int k=1;k<=7;++k)printf("%d",gw(zi,k-1));}

int main(){
	lim=(1<<7)-1;
    int cases;scanf("%d",&cases);while(cases--){
    	scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%d%d",t+i,b+i);
    	memset(dp,0x3f,sizeof(dp));
    	int qh=1,qt=0;
    	q[++qt]=(dul){0,0,lim},dp[0][0][lim]=0;
    	
    	
    	while(qh<=qt){
    		int i=q[qh].a,j=q[qh].b,zi=q[qh].c;++qh;
    		for(int k=1;k<=7;++k)if(!gw(zi,k-1)&&vad1(i,zi,k)){
    			int &f=dp[i][k][zi|mi2(k-1)];
    			if(f==inf)q[++qt]=(dul){i,k,zi|mi2(k-1)};
    			f=min(f,i==0?0:dp[i][j][zi]+(t[i-j]^t[i-k]));
    		}
    		for(int k=1;k<=7;++k)if(vad2(i,zi,k)){
    			int zz=(zi<<k)|mi2(k-1);zz&=lim;
    			int &f=dp[i+k][0][zz];
    			if(f==inf)q[++qt]=(dul){i+k,0,zz};
    			f=min(f,i==0?0:dp[i][j][zi]+(t[i-j]^t[i+k]));
    		}
    	}
    	int ans=inf;
    	for(int k=0;k<=7;++k)ans=min(ans,dp[n][k][lim]);
    	printf("%d
",ans);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/happyguy/p/13672369.html