被这道神仙的差分约束卡了两个小时。。。
对于约束条件真的要考虑的非常周全,并且这题是时间段,改段为点细节还是很多。
设s[i]表示0点~i点时间段要雇多少人
因为每一天需要的人手为c[i],有: s[i]-s[i-8]>=c[i] (1<=i<=8) 和 s[i]+s[24]-s[i-8]>=c[i] (9<=i<=24)
因为每一天至多雇t[i]个人,有: s[i]-s[i-1]<=t[i] 并且为了产生正环加入条件 s[i-1]-s[i]<=0
考虑二分s[24]的值,进行差分约束
为了控制s[24]的值只能为mid,有s[0]-s[24]<=mid 和 s[24]-s[0]>=mid
由于读入方式的不一样,题意人出现的时间段的编号是我定义的时间段编号-1(坑了我很久),要t[x+1]++;
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int c[30],t[30]; struct node { int x,y,d,next; }a[2100];int len,last[30]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } int d[30],list[30];bool v[30]; bool check(int mid) { len=0;memset(last,0,sizeof(last)); for(int i=1;i<=7;i++)ins(i+16,i,c[i]-mid); for(int i=8;i<=24;i++)ins(i-8,i,c[i]); for(int i=1;i<=24;i++)ins(i,i-1,-t[i]),ins(i-1,i,0); ins(24,0,-mid);ins(0,24,mid); memset(d,-63,sizeof(d));d[0]=0; memset(v,false,sizeof(v));v[0]=true; int head=1,tail=1;list[tail++]=0; while(head!=tail) { int x=list[head]; if(x==24&&d[x]>mid)return false; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(d[y]<d[x]+a[k].d) { d[y]=d[x]+a[k].d; if(v[y]==false) { v[y]=true; list[tail++]=y; if(tail==28)tail=1; } } } v[x]=false; head++;if(head==28)head=1; } return true; } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); int T; scanf("%d",&T); while(T--) { for(int i=1;i<=24;i++)scanf("%d",&c[i]); int P,x; scanf("%d",&P); memset(t,0,sizeof(t)); for(int i=1;i<=P;i++) scanf("%d",&x), t[x+1]++; int l=1,r=P,ans=-1; while(l<=r) { int mid=(l+r)/2; if(check(mid)) { ans=mid; r=mid-1; } else l=mid+1; } if(ans==-1)printf("No Solution\n"); else printf("%d\n",ans); } return 0; }