HDU 3572 Task Schedule

版权声明:本人QQ 249712949 欢迎交流算法(请备注)。 https://blog.csdn.net/coord_/article/details/88544280

传送门

作业调度,这道题还真没想到能用网络流。。。。乍一看跟背包问题差不多。
N个作业,M个机器,每个作业给你一个耗费时间(时间段)以及最早开始时间和最晚完成时间(这两个是时间点),单位是天。一个作业同时只能被一个机器做,一个机器同时也只能做一个作业,但是,可以只做一部分,之后可以切换别的机器做。一部分指的是整数天。
在这里插入图片描述
画个图。把数据处理成上面这个图,然后按照最大流求解就ojbk了,看看最后的最大流是不是P1+P2+P3+...+PN(最大流必然小于等于这个,因为从源点输出就这么些)
源点输出到每个作业,权值等于这个作业的耗费时间P,代表你这个作业要处理P次(每次1天);然后的N+1,N+2这些代表具体的某一天(整体上不一定连续每天都有,要根据每个作业的上下限来定),比如第一个作业的上下限是[N+1,N+3],那么就把这个作业和这个上下限内的每一天都连上一条边,权值是1(此时不用关心这个作业的花费时间,因为前面从源点连的边已限制这一点),权值是1表示某一天内只能处理这个作业1天的完成量(这不是废话么);然后,代表某一天的每个点都要和汇点连上一条权值为M的边,代表这一天最多能同时处理M个作业(因为机器只有M个)。
这个图并不关心某个作业被具体哪些机器处理,因为这个不重要。只关心某个作业必须在哪些天内被处理,以及某一天最多同时处理多少个作业。

这个题还有个问题,就是他没说清楚P<=E-S还是P<=E-S+1。这关系到在上面的图中某个作业要连接E-S个点还是E-S+1个点。
当然,在样例中的第二个输出为Yes说明了是后者。但是真的够sb的。

【19.3.18 想法】今天结合HDU 2883这个题,突然想到一个问题:该方法怎么保证某机器某一天一定处理某任务1天的工作量?而不是0.5个工作量?(也就是说从某任务点某天数点的流量会不会大于0小于1?)
答案是不会的,因为P_NM这些值都是整数且大于等于1,考虑最大流算法寻找增广路的过程,权值为1的边肯定是整条路上权值最小的边,这条路的流量不可能比1再小了。

dinic

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
using namespace std;

const int MAX = 500 + 500 + 2 + 10;
const int INF = 1e9;
int N, M, T;
int flow;
int sum;

struct Edge
{
	int f, t, flow, cap;
};
vector<Edge> ve;
vector<int> v[MAX];

int P, S, E;
bool vis[MAX];
int level[MAX];
int cur[MAX];

void addEdge(int from, int to, int weight)
{
	ve.push_back(Edge{ from,to,0,weight });
	ve.push_back(Edge{ to,from,0,0 });
	v[from].push_back(ve.size() - 2);
	v[to].push_back(ve.size() - 1);
}

void init()
{
	ve.clear();
	for (int i = 0; i <= N + 500 + 1; i++)
		v[i].clear();
	flow = sum = 0;
	memset(vis, 0, sizeof vis);
}

bool bfs(int t)
{
	memset(level, -1, sizeof level);
	queue<int> q;
	q.push(0);
	level[0] = 0;
	for (; !q.empty();)
	{
		int x = q.front();
		q.pop();
		for (int i = 0; i < v[x].size(); i++)
		{
			Edge &e = ve[v[x][i]];
			if (level[e.t] < 0 && e.flow < e.cap)
			{
				level[e.t] = level[x] + 1;
				q.push(e.t);
			}
		}
	}
	return level[t] >= 0;
}

int dfs(int n, int t, int f)
{
	if(n == t || f == 0) return f;                   //
	for (int& i = cur[n]; i < v[n].size(); i++)
	{
		Edge& e = ve[v[n][i]];
		int f0;
		if (level[e.t] == level[n] + 1 && (f0 = dfs(e.t, t, min(f, e.cap - e.flow))) > 0)
		{
			e.flow += f0;
			ve[v[n][i] ^ 1].flow -= f0;
			return f0;
		}
	}
	return 0;
}

int main()
{
	scanf("%d", &T);
	for (int cnt = 1; cnt <= T; cnt++)
	{
		scanf("%d%d", &N, &M);
		init();
		for (int i = 1; i <= N; i++)
		{
			scanf("%d%d%d", &P, &S, &E);
			if (P > E - S + 1)                      //
			{
				printf("Case %d: No\n\n", cnt);
				return 0;
			}
			addEdge(0, i, P);
			for (int j = S; j <= E; j++)
			{
				addEdge(i, j + N, 1);
				//addEdge(j + N, 500 + N + 1, M);
				vis[j + N] = true;
			}
			sum += P;
		}
		for (int i = N + 1; i <= N + 500; i++)
			if (vis[i])
				addEdge(i, N + 500 + 1, M);

		for (; bfs(N + 500 + 1);)
		{
			memset(cur, 0, sizeof cur);
			int temp;
			for (; temp = dfs(0, N + 500 + 1, INF);)
				flow += temp;
			//cout << flow;
		}
		printf("Case %d: %s\n\n", cnt, flow == sum ? "Yes" : "No");
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/coord_/article/details/88544280