hdu 3572 Task Schedule(最大流)

                                    Task Schedule

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


Problem Description
Our geometry princess XMM has stoped her study in computational geometry to concentrate on her newly opened factory. Her factory has introduced M new machines in order to process the coming N tasks. For the i-th task, the factory has to start processing it at or after day Si, process it for Pi days, and finish the task before or at day Ei. 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), indicating the number of test cases.

You are given two integer N(N<=500) and M(M<=200) on the first line of each test case. Then on each of next N lines are three integers Pi, Si and 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 x 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
 

一、原题地址

        点我传送


二、大致题意

    现在有n项任务,将分配给m个机器去做。每个任务有他的持续时间Pi,  开始时间Si(或者在这个时间之后开始任务),结束时间Ei(或者在这个时间之前结束任务)。每项任务可以零零碎碎的分配给每台机器,即它能被分成好几段来完成。但是每台机器一天是只能去接受一项任务的。


三、大致思路

    我们将每一项任务看作一个点,因为任务完成的天数最多是500天,所以我们可以把每一天也看作是一个个点。

    建立一个超级源点,将它与所有的任务点相连,那么这里每条边的容量也就自然是这个任务点所需被工作的时间Pi。

    每个任务点应该与他对应的可以被工作的天数点相连,容量为1

    最后再将所有天数点连接超级汇点,因为有m台机器,也就是说每天最多只能完成m段任务,那么这些边的容量就是m了。

    完成了建图以后,套入Dinic。只需要判断汇点的最大流量是否等于所有任务需求的总量就可以了。


四、代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int inf = 0x3f3f3f3f;
#define LL long long int 
long long  gcd(long long  a, long long  b) { return a == 0 ? b : gcd(b % a, a); }


int T;
int n, m;
int sum;
const int maxn = 1005;
struct Edge
{
	Edge() {}
	Edge(int from, int to, int cap, int flow) :from(from), to(to), cap(cap), flow(flow) {}
	int from, to, cap, flow;
};

struct Dinic
{
	int n, m, s, t;            //结点数,边数(包括反向弧),源点与汇点编号
	vector<Edge> edges;     //边表 edges[e]和edges[e^1]互为反向弧
	vector<int> G[maxn];    //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
	bool vis[maxn];         //BFS使用,标记一个节点是否被遍历过
	int d[maxn];            //从起点到i点的距离
	int cur[maxn];          //当前弧下标

	void init(int n, int s, int t)
	{
		this->n = n, this->s = s, this->t = t;
		for (int i = 1; i <= n; i++) G[i].clear();
		edges.clear();
	}

	void AddEdge(int from, int to, int cap)
	{
		edges.push_back(Edge(from, to, cap, 0));
		edges.push_back(Edge(to, from, 0, 0));
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}

	bool BFS()
	{
		memset(vis, 0, sizeof(vis));
		queue<int> Q;//用来保存节点编号的
		Q.push(s);
		d[s] = 0;
		vis[s] = true;
		while (!Q.empty())
		{
			int x = Q.front(); Q.pop();
			for (int i = 0; i<G[x].size(); i++)
			{
				Edge& e = edges[G[x][i]];
				if (!vis[e.to] && e.cap>e.flow)
				{
					vis[e.to] = true;
					d[e.to] = d[x] + 1;
					Q.push(e.to);
				}
			}
		}
		return vis[t];
	}

	int DFS(int x, int a)
	{
		if (x == t || a == 0)return a;
		int flow = 0, f;//flow用来记录从x到t的最小残量
		for (int& i = cur[x]; i<G[x].size(); i++)
		{
			Edge& e = edges[G[x][i]];
			if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
			{
				e.flow += f;
				edges[G[x][i] ^ 1].flow -= f;
				flow += f;
				a -= f;
				if (a == 0) break;
			}
		}
		return flow;
	}

	int Maxflow()
	{
		int flow = 0;
		while (BFS())
		{
			memset(cur, 0, sizeof(cur));
			flow += DFS(s, inf);
		}
		return flow;
	}
};
void solve()
{
	scanf("%d %d", &n, &m);
	Dinic DC;
	int sum = 0;
	DC.init(500 + n + 2, 0, 500 + 1 + n);
	for (int i = 1; i <= n; i++)
	{
		int w, u, v;
		scanf("%d %d %d", &w, &u, &v);
		sum += w;
		DC.AddEdge(0, i, w);
		for (int j = n + u; j <= n + v; j++)
		{
			DC.AddEdge(i, j, 1);
		}
	}
	for (int i = n + 1; i <= n + 500; i++)
	{
		DC.AddEdge(i, 500 + n + 1, m);
	}
	int ans = DC.Maxflow();
	if (sum == ans)printf("Yes\n");
	else printf("No\n");
}
int main()
{
	int Kase = 1;
	scanf("%d", &T);
	while (T--)
	{
		printf("Case %d: ", Kase++);
		solve();
		printf("\n");
	}
	getchar();
	getchar();
}

    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值