poj 1275 差分

x[i]表示第i-1时开始工作的人
r[i]表示第i-i时开始工作的至少多少人
s[i]表示从0点开始一直到i-1时开始工作的人,
num[i]表示第i-1时来应聘的总人数;

求最少,用最长路  ans招聘总人数;//0=24
s[i]-s[i-8]>=r[i](当i>=9)
s[i]-s[i-1]>=0;
s[i]-s[i-1]<=num[i];
s[i]-s[i+16]+ans>=r[i];//ans-s[i+16]为 第一天的还在工作的人
s[24]-s[0]>=ans;
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int tp,nex[1004],tov[1004],in[30],tow[1004],h[30];
int r[30],num[30],s[30],q[10005],vis[30],dis[30],n;
void add(int x,int y,int w)
{
	tp++;
	nex[tp]=h[x];
	tow[tp]=w;
	tov[tp]=y;
	h[x]=tp;
}
bool spfa(int he)
{
	memset(vis,0,sizeof(vis));
	memset(q,0,sizeof(q));
	memset(in,0,sizeof(in));
	for(int i=0;i<=24;i++)
	dis[i]=-1;
	dis[0]=0;
	vis[0]=1;
	int head=0,tail=1;
	q[tail]=0;
	while(head<tail)
	{
		head++;
		int x=q[head];
		in[x]++;
		if(in[x]>24)return 0;
		for(int i=h[x];i;i=nex[i])
		{
			int v=tov[i];
			if(dis[v]<dis[x]+tow[i])
			{
				dis[v]=dis[x]+tow[i];
				if(vis[v]==0)
				{
					tail++;
					vis[v]=1;
					q[tail]=v;
				}
			}
		}
		vis[x]=0;
	}
	if(dis[24]==he){return 1;
	}
	return 0;
}
void build(int ans)
{
	add(0,24,(-1)*ans);
  for(int i=1;i<=24;i++)
  {
  	add(i,i-1,(-1)*num[i]);
  	add(i-1,i,0);
  }  
  for(int i=1;i<=8;i++)  
    add(i+16,i,r[i]-ans);
  for(int i=9;i<=24;i++)
  {
  	 add(i-8,i,r[i]);
  } 
}
int main()
{
	int t;
   cin>>t;
   for(int z=1;z<=t;z++)
   {
   	memset(num,0,sizeof(num));
   for(int i=1;i<=24;i++)
   	{
   		scanf("%d",&r[i]);
   	}
   	cin>>n;
   	for(int i=1;i<=n;i++)
   	{
   		int x;
   		scanf("%d",&x);
		     num[x+1]++;  
   	}
   	int flag=0;
   	for(int i=0;i<=n;i++)
   	{	tp=0;
	   memset(h,0,sizeof(h));
   		build(i);
   		if(spfa(i)==1)
   		{
   		printf("%d\n",i);flag=1;
		break;   	
   		}
   	}	if(flag==0)printf("No Solution\n");
   }
   return 0;	
}

猜你喜欢

转载自blog.csdn.net/Bluelanzhan/article/details/80304835