分任务建图(HDU - 3572 为例)

题意:

某工厂有 M 台机器要完成 N 个任务。 第i个任务的开始时间不早于Si, 需要干Pi天, a并要在不晚于Ei时完成. 一台机器一天只能干一个任务,一个认为在同一天只能用一台机器. 任务完成不需要连续,只要有足够的天数即可。 
问能不能搞完这些工作 

显然,如果我没学网络流,我会认为这时dp,不过他确实是网络流。因为状态转移方程应该是可求的,但是没加应该任务就相当于多了一个转移方向,那么转移方程会非常复杂,所以我们讲网络流做法//更重要的是,DP是我队友的主力,推方程的能力还堪忧,就不提他(@我的名字叫easy)了。

好了,我们已经知道他是网络流了,我们开始工作。第一步,addedge,把边建出来,然后图搞出来就完了。

网络流的原点和汇点在这里没有什么意义了,只是为图提供出入口

因为网络流只有边在参与运算,没有点的事情,所以想把点搞出来是不可能的,不妨把从原点到事件的边当作事件节点,这样变的权值就是W,从每个任务到区间内的每一天的的边权值为1(因为一天一个任务只能占一台机器),然后让每一天连向汇点,这代表着这一天完成的工作量,因为机器只有那么多,所以每条路的权值为M。图建出来了,比较最大流量和总任务数就完了。

算法选择 dinic

代码实现如下

/*链式前向星建图,CPP代码如下
*@author SunnVei
*@date 2018-5-4
*/
#include <set>
#include <queue>#include <vector>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <iostream>using namespace std;const int INF = 0x3f3f3f3f;struct node {int u, v, cap;node() {}node(int u, int v, int cap) :u(u), v(v), cap(cap) {}}es[5000005];int R, S, T;int dis[5005], iter[5005];vector<int> tab[5005];void addedge(int u, int v, int cap) {tab[u].push_back(R);es[R++] = node(u, v, cap);tab[v].push_back(R);es[R++] = node(v, u, 0);}int bfs() {int i, h;queue<int> q;q.push(S);memset(dis, INF, sizeof(dis));dis[S] = 0;while (q.size()) {h = q.front();q.pop();for (i = 0; i<tab[h].size(); i++) {node &e = es[tab[h][i]];if (e.cap>0 && dis[e.v] == INF) {dis[e.v] = dis[h] + 1;q.push(e.v);}}}return dis[T]<INF;}int dfs(int x, int maxflow) {int flow;if (x == T)return maxflow;for (int &i = iter[x]; i<tab[x].size(); i++) {node &e = es[tab[x][i]];if (dis[e.v] == dis[x] + 1 && e.cap>0) {flow = dfs(e.v, min(maxflow, e.cap));if (flow) {e.cap -= flow;es[tab[x][i] ^ 1].cap += flow;return flow;}}}return 0;}int dinic() {int ans, flow;ans = 0;while (bfs()) {memset(iter, 0, sizeof(iter));while (flow = dfs(S, INF))ans += flow;}return ans;}int main() { int n, m, t, i, j, u, v, w, cas, sum; scanf("%d", &t); for (cas = 1; cas <= t; cas++) { scanf("%d%d", &n, &m); R = S = sum = 0, T = 1005; for (i = 0; i <= T; i++) tab[i].clear();for (i = 1; i <= n; i++) {scanf("%d%d%d", &w, &u, &v);addedge(0, i, w);for (j = u + n; j <= v + n; j++)addedge(i, j, 1);sum += w;}for (i = 1; i <= 500; i++)addedge(i + n, T, m);if (sum == dinic())printf("Case %d: Yes\n\n", cas);elseprintf("Case %d: No\n\n", cas);}return 0;}

猜你喜欢

转载自blog.csdn.net/qq_41104612/article/details/80197601