zoukankan      html  css  js  c++  java
  • pku 1275 Cashier Employment

    【题目大意】: 给出一个超市24小时各需要R[i]个雇员工作,有N个雇员可以雇佣,他们开始工作时间分别为A[i],求需要的最少的雇员人数。

    这题目在黑书上有详细的解析,题目的关键是在构图上,把约束条件找出来,再按照条件加边就OK了,不过,我是参考课件里面才过的

    【算法分析】: 用差分约束,难点是建立模型。设X[i]0-i小时内工作的人数(X[24]即为所求)R[i]为第(i-1)-i小时时需要在工作的人数,A[i]可以在第i-1小时开始工作。可以建立起以下约束不等式:

    0 <= X[i]-X[i-1] <= A[i];  1 <= I <= 24;

    X[i] – X[i-8] >= R[i];   8 <= I <= 24;

    X[24] – (X[16+i]-X[i]) >= R[i];  1 <= I < 8;

    统一化为<=不等式,则可化为求X[0]-X[24] <= --ans; 即求240的最短距离。如果化为>=不等式,则比较直观,X[24]- X[0] >= ans; 024的最长距离。如果有圈出现则无解。二分答案找到最小的ans,使得约束系统有解。特别注意一点,X[24]-X[0] >= ans也是要作为一个约束不等式,添加(0, 24, ans)的边。

    #include<iostream>
    #include<string>
    #define MAXINT 9999999
    #define MAXN 30
    using namespace std;
    int dis[MAXN],num;
    int n,m,r[25],t[25];
    //r[],(i-1)-i小时内需要工作人数.
    //t[],第(i-1)小时可以开始工作的人数.
    struct edge
    {
    	int u,w,v;
    }e[MAXN*5];
    void add(int u,int v,int w)
    {
    	e[num].u=u;
    	e[num].w=w;
    	e[num].v=v;
    	 num++;
    }
    bool bellman_ford()
    {
    	for(int i=0;i<=24;i++)
    		dis[i]=-MAXINT;
    	dis[24]=0;
    	bool rel=false;
    	for(int i=1;i<=24;i++)
    	{
    		for(int j=0;j<num;j++)
    		{
    			int x=e[j].v;
    			if(dis[x]>dis[e[j].u]+e[j].w)
    			{
    				dis[x]=dis[e[j].u]+e[j].w;
    				rel=true;
    			}
    		}
    		if(!rel) //没有可松弛操作,则一定有解了
    			return true;
    	}
    	for(int j=0;j<num;j++)
    	{
    		int x=e[j].v;
    		if(dis[x]>dis[e[j].u]+e[j].w)
    			return false;
    	}
    	return true;
    }
    int main()
    {
    	int n1,cas,a,minn,maxn;
    	cin>>cas;
    	while(cas--)
    	{	
    		minn=-1;
    		memset(t,0,sizeof(t));
    		for(int i=1;i<=24;i++)
    		{
    			cin>>r[i];
    			if(r[i]>minn) minn=r[i];
    		}
    		cin>>n1;
    		maxn=n1;
    		//因为最少要有max(r[i])个人,最多有n1个人。
    		for(int i=0;i<n1;i++)
    		{
    			cin>>a;
    			t[++a]++;
    		}
    		num=0;
    		for(int i=1;i<=24;i++)
    		{
    			add(i-1,i,t[i]);
    			add(i,i-1,0);
    		}
    		for(int i=8;i<=24;i++)
    			add(i,i-8,-r[i]);
    		int edge_num=num;//edge_num保存已经加好的边数
    		int res=-1;
    		int left=minn,right=maxn,mid;
    		while(left<=right)//二分枚举答案
    		{
    			num=edge_num;
    			mid=(right+left)/2;
    			for(int i=1;i<8;i++)
    				add(i,i+16,-r[i]+mid);
    			add(24,0,-mid);
    			//这里其实有个隐藏的约束条件X[24]-X[0]>=mid
    			//转换为X[0]-X[24] <= -mid;
    			if(bellman_ford())//如果有解,那么再找更小的解
    			{
    				right=mid-1;res=mid;
    			}
    			else left=mid+1;
    		}
    		if(res==-1)
    			cout<<"No Solution"<<endl;
    		else cout<<res<<endl;
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    String驻留带来的危害
    Go语言的堆栈分析
    SecureCRT使用技巧
    Javascript中相同Function使用多个名称
    记录Office Add-in开发经验
    Silverlight和WPF中DataContractJsonSerializer对时间的处理差异
    ASP.NET MVC项目实践技巧
    有点担心Node.js的未来了
    回首经典的SQL Server 2005
    duilib关于学习Demo中的QQ
  • 原文地址:https://www.cnblogs.com/nanke/p/2139349.html
Copyright © 2011-2022 走看看