zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
    
  • 相关阅读:
    解决Ubuntu下pycharm无法输入中文的问题
    爬取www.mmjpg.com网站图片,你懂得哦!
    批量查询ip地址归属地
    Opencv源码编译
    使用阿里云安装python模块
    Ansible运维自动化
    Mha-Atlas-MySQL高可用
    SVN
    Tomcat
    DHCP
  • 原文地址:https://www.cnblogs.com/happyguy/p/13672369.html
Copyright © 2011-2022 走看看