「HDU3572」Task Schedule【最大流】

本文探讨了在有限机器资源下,如何通过最大流算法解决任务调度问题,确保所有任务在规定时间内完成。介绍了问题背景,包括任务的时间限制和机器的工作能力,并详细解析了最大流算法在网络流图上的应用。

Task Schedule

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 12914 Accepted Submission(s): 3895

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-thith 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(T20), indicating the number of test cases.

You are given two integer N(N≤500)N(N\leq 500)N(N500) and M(M≤200)M(M\leq 200)M(M200) 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(1Pi,Si,Ei500), 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_flowi=1nPi则表示可以完成

代码

#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");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值