Description
Input
Output
Sample Input
1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 5 0 23 22 1 10
Sample Output
1
分析:
约束条件:约束条件分析,为方便分析,我们把讨论区间由[0,23]改为[1,24] :设apply[i] 为来应聘的在第i个小时开始工作的总人数设R[i] 为第i个小时至少需要的人数设X[i] 为实际雇佣的在第i个小时开始工作的总人数设S[i] = X[1] + … + X[i] (第1到第i个小时一共雇佣的总人数)
由于0<=x[i]<=apply[i],于是
1> s[i]-s[i-1]>=0; 2> s[i]-s[i-1]<=apply[i] <=> s[i-1]-s[i]>=-apply[i];
由于题目限制:
3> s[i]-s[i-8]>=R[i](8<=i<=24) 4> s[i]-s[i+16]>=R[i]-s[24] (i<8) (*)
(*)不等式中,s[24](也是最后要求的)为变量,于是需要二分答案;
二分答案为p后,注意假设了s[24]==p;
于是 5> s[24]-s[0]>=p && s[0]-s[24]<= -p;
注意,这一条必须加入图中一起跑,不能最后单独判定,因为s[24]不是一个独立的变量,与其他变量有关。
最后,求最小,跑最长路即可。
代码如下:
another version<pre name="code" class="cpp">#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<vector> #define LL long long #define CLEAR(XXX) memset((XXX),0,sizeof(XXX)) using namespace std; const int inf=1e9; const int maxn=1000+5,maxm=100005; int n,apply[30],R[30]; inline void _read(int &x){ char ch=getchar(); bool mark=false; for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true; for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0'; if(mark)x=-x; } struct Edge{ int from,to,w; Edge(int from,int to,int w):from(from),to(to),w(w){} }; vector<Edge> edge; int last[maxm],Next[maxm]; int dist[maxn]; int cnt[maxn]; bool vis[maxn]; struct SPFA{ int n,m; void init(int n){ this->n = n; m=0; CLEAR(last); CLEAR(Next); edge.clear(); edge.push_back(Edge(0,0,0)); } void add_edge(int from,int to,int dist){ edge.push_back(Edge(from,to,dist)); m=edge.size()-1; Next[m]=last[from]; last[from]=m; } bool solve(int s){ int i; CLEAR(vis); CLEAR(cnt); for(i=1;i<=n;i++) dist[i]= -inf; dist[s]=0; vis[s]=true;cnt[s]++; queue <int> q; q.push(s); while(!q.empty()){ int x=q.front(); q.pop();vis[x]=false; for(i=last[x];i;i=Next[i]){ Edge& e=edge[i]; if(dist[e.from]+e.w>dist[e.to]){ //最少,用最长路 dist[e.to]=dist[e.from]+e.w; if(!vis[e.to]){ cnt[e.to]++; if(cnt[e.to]==n+1)return false; q.push(e.to) ; vis[e.to]=true; } } } } return true; } void answer(){ for(int i=1;i<=n;i++) if(dist[i]>=inf)printf("NoPath\n"); else printf("%d\n",dist[i]); } }; SPFA solver; bool check(int p){ //二分ans,就是s[24]; int i; solver.init(24); for(i=1;i<=24;i++){ solver.add_edge(i-1,i,0); //1> s[i]-s[i-1]>=0; solver.add_edge(i,i-1,-apply[i]); //2> s[i]-s[i-1]<=apply[i] <=> s[i-1]-s[i]>=-apply[i]; solver.add_edge(0,i,0); if(i>=8)solver.add_edge(i-8,i,R[i]); //3> s[i]-s[i-8]>=r[i]; (8<=i<=24) else solver.add_edge(i+16,i,R[i]-p); //4> s[i]-s[i+16]>=r[i]+p } solver.add_edge(0,24,p); // 5> dist[24]-dist[0]==p; solver.add_edge(24,0,-p); return solver.solve(0); } int main(){ //freopen("ans.out","w",stdout); int t,i,x,j,l,r,y; _read(t); while(t--){ CLEAR(R); CLEAR(apply); for(i=1;i<=24;i++)_read(R[i]); _read(n); for(i=1;i<=n;i++){ _read(x); apply[x+1]++; } l=0;r=n; while(l<=r){ int mid=(l+r)>>1; check(mid)? (r=mid-1):(l=mid+1); } if(check(l)&&l<=n)printf("%d\n",l); else puts("No Solution"); } return 0; }
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> const int inf=-1e9; using namespace std; int dis[5005],next[100005],last[100005]; bool vis[5005]; int cnt[5005]; int num[25]; int r[25]; int m=0; int n=24; struct edge{ int from,to,len; edge(){} edge(int a,int b,int c){from=a;to=b;len=c;} }; edge line[100005]; inline void read(int &x){ char t; bool mark=false; for(;t=getchar(),t<'0'||t>'9';) if(t=='-') mark=1; for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar()); x=mark?-x:x; } void add_edge(int from,int to,int len){ m++; next[m]=last[from]; last[from]=m; line[m]=edge(from,to,len); } void check_clear(){ memset(next,0,sizeof(next)); memset(last,0,sizeof(last)); memset(dis,0,sizeof(dis)); memset(line,0,sizeof(line)); } void init_clear(){ memset(next,0,sizeof(next)); memset(last,0,sizeof(last)); memset(dis,0,sizeof(dis)); memset(line,0,sizeof(line)); memset(r,0,sizeof(r)); } bool spfa(int s){ queue<int>q; memset(vis,0,sizeof(vis)); memset(cnt,0,sizeof(cnt)); int i,j,k,t; for(i=1;i<=n;i++)dis[i]=inf; vis[s]=true; dis[s]=0; cnt[s]++; q.push(s); while(q.size()){ t=q.front();q.pop();vis[t]=false; for(i=last[t];i;i=next[i]){ if(dis[line[i].to]<dis[line[i].from]+line[i].len){ dis[line[i].to]=dis[line[i].from]+line[i].len; if(vis[line[i].to]==false){ cnt[line[i].to]++; if(cnt[line[i].to]>=n+1){ return false; } q.push(line[i].to); vis[line[i].to]=true; } } } } return true; } bool check(int mid){ check_clear(); bool flag; int i,j,k; m=0; for(i=1;i<=24;i++)add_edge(i-1,i,0); for(i=1;i<=24;i++)add_edge(i,i-1,-num[i]); for(i=8;i<=24;i++)add_edge(i-8,i,r[i]); for(i=1;i<=7;i++)add_edge(i+16,i,r[i]-mid); for(i=1;i<=24;i++)add_edge(0,i,0); add_edge(0,24,mid); add_edge(24,0,-mid); flag=spfa(0); //if(flag==false)cout<<m id<<" fuck"<<endl; //else cout<<mid<<" "<<dis[24]<<" "<<dis[0]<<endl; if(flag==false)return false; //if(dis[n]>mid)return false; else return true; } int main(){ int h; cin>>h; while(h--){ //s[i]-s[i-1]>=0 //s[i-1]+num[i]>=s[i] //s[i]-s[i-8]>=num[i] (8=<i<=24) //s[24]-s[i+16]+s[i]>=r[i] (1<=i<=7) init_clear(); int minn=1,maxn,tot; int i,j,k,x; m=0; for(i=1;i<=24;i++)scanf("%d",&r[i]); scanf("%d",&tot); for(i=1;i<=tot;i++){ scanf("%d",&x); num[x+1]++; } maxn=tot; while(minn<=maxn){ int mid=(minn+maxn)/2; if(check(mid))maxn=mid-1; else minn=mid+1; } if(check(minn)==false)cout<<"No Solution"<<endl; else cout<<minn<<endl; } }