Task Schedule
Problem Description
Our geometry princess XMM has stoped her study in computational geometry to concentrate on her newly opened factory. Her factory has introduced MMM new machines in order to process the coming NNN tasks. For the i−thi-thi−th task, the factory has to start processing it at or after day SiS_iSi, process it for PiP_iPi days, and finish the task before or at day EiE_iEi. A machine can only work on one task at a time, and each task can be processed by at most one machine at a time. However, a task can be interrupted and processed on different machines on different days.
Now she wonders whether he has a feasible schedule to finish all the tasks in time. She turns to you for help.
Input
On the first line comes an integer T(T≤20)T(T\leq20)T(T≤20), indicating the number of test cases.
You are given two integer N(N≤500)N(N\leq 500)N(N≤500) and M(M≤200)M(M\leq 200)M(M≤200) on the first line of each test case. Then on each of next NNN lines are three integers Pi,SiP_i, S_iPi,Si and Ei(1≤Pi,Si,Ei≤500)E_i (1\leq P_i, S_i, E_i\leq 500)Ei(1≤Pi,Si,Ei≤500), which have the meaning described in the description. It is guaranteed that in a feasible schedule every task that can be finished will be done before or at its end day.
Output
For each test case, print “Case x: ” first, where xxx is the case number. If there exists a feasible schedule to finish all the tasks, print “Yes”, otherwise print “No”.
Print a blank line after each test case.
Sample Input
2
4 3
1 3 5
1 1 4
2 3 7
3 5 9
2 2
2 1 3
1 2 2
Sample Output
Case 1: Yes
Case 2: Yes
Source
2010 ACM-ICPC Multi-University Training Contest(13)——Host by UESTC
题意
- nnn个任务,mmm个机器,每个任务都有一个开始时间限制,结束时间限制,即限制在[Si,Ei][S_i,E_i][Si,Ei]内完成,每个任务完成需要的时间是一定的,每个任务可以间断完成,可以更换机器完成
题解「最大流」
- 众所周知,网络流的题基本都是建好图然后跑相关算法就行了,关键就是建好图,理解每条建的边的含义是关键
- 这题建边我分为三个层面
- 从超级源点sss 向每一个任务建立容量为infinfinf的边,怎么理解这里的infinfinf呢?实际上虽然建立了超级源点sss,但是个人认为可以吧源点认为是所有的任务顶点,超级源点sss只是为了方便跑最大流,我们知道在最大流算法中,流入源点的流量其实是没有限制的,为infinfinf,同理,对于这个图,所有的源点【所有的任务顶点】流入的流量应该设为infinfinf,即超级源点到任务顶点的有向边的容量设为infinfinf
- 将时间断分成顶点,每个顶点表示每个单位时间,从每个这些顶点向超级汇点ttt连边,容量设为mmm,表示每个单位时间点内最多有mmm台机器同时工作
- 由每个任务顶点iii向每一个[Si,Ei][S_i,E_i][Si,Ei]内的单位时间顶点连边,容量设为111,表示这个时间点内能完成每个任务的单位时间内的子任务
- 现在你大概知道怎么判断了吧,跑最大流,即值为max_flowmax\_flowmax_flow若
max_flow≥∑i=1nPimax\_flow \geq \sum_{i=1}^{n}{P_i}max_flow≥i=1∑nPi则表示可以完成
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=1e3+10;
const int maxm=6e5+10; //注意每条边都有反向边
#define inf 0x3f3f3f3f
int dis[maxn],head[maxn],id[maxn],tot,n,m;//id:当前弧优化,即记录可用的最远的那条边
struct node{
int to,w,next;
node(int a=0,int b=0,int c=0){
to=a;w=b;next=c;
}
}edge[maxm];
void add_edge(int u,int v,int w)
{
edge[++tot]=node(v,w,head[u]);
head[u]=tot;
}
bool bfs(int s,int t)
{
queue<int> que;que.push(s);
for(int i=1;i<maxn;i++) dis[i]=0,id[i]=head[i];dis[s]=1;
while(!que.empty()){
int cur=que.front();que.pop();
for(int i=head[cur];i!=-1;i=edge[i].next){
int nxt=edge[i].to;
if(edge[i].w&&!dis[nxt]){
dis[nxt]=dis[cur]+1;
que.push(nxt);
if(nxt==t) return 1;
}
}
}
return 0;
}
int dfs(int cur,int flow,int s,int t)
{
if(cur==t) return flow;
int rest=flow;
for(int i=id[cur];i!=-1&&rest;i=edge[i].next){
id[cur]=i;
if(edge[i].w&&dis[edge[i].to]==dis[cur]+1){
int f=dfs(edge[i].to,min(rest,edge[i].w),s,t);
edge[i].w-=f;
edge[i^1].w+=f;
rest-=f;
}
}
return flow-rest;
}
inline int dinic(int s,int t)
{
int maxflow=0,flow;
while(bfs(s,t)) while((flow=dfs(s,inf,s,t))) maxflow+=flow;
return maxflow;
}
int main()
{
int test,s=1001,t=1002;scanf("%d",&test);
for(int cas=1;cas<=test;cas++){
scanf("%d %d",&n,&m);
memset(head,-1,sizeof(head));tot=-1;int sum=0;
for(int i=1;i<=n;i++) add_edge(s,i,inf),add_edge(i,s,0);
for(int i=501;i<=1000;i++) add_edge(i,t,m),add_edge(t,i,0);
for(int i=1,tim,start,end;i<=n;i++){
scanf("%d %d %d",&tim,&start,&end);
sum+=tim;
for(int j=start;j<=end;j++) add_edge(i,500+j,1),add_edge(500+j,i,0);
}
printf("Case %d: ",cas);
printf(dinic(s,t)>=sum?"Yes\n\n":"No\n\n");
}
}