传送门
作业调度,这道题还真没想到能用网络流。。。。乍一看跟背包问题差不多。
有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_N
、M
这些值都是整数且大于等于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;
}