题目链接:acm.hdu.edu.cn/showproblem.php?pid=4494
题意:相当于给n个任务,给出每个任务的开始时间和持续时间,每个任务需要不同种类的人来完成,种类之间的人彼此独立不能互换,对于某个任务的人在完成任务后可以赶往其他任务帮忙,问你最少需要多少人才能完成任务
思路:
最大流:这题和最小路径覆盖思想很像,只是每个点覆盖的次数不同了,所以可以拆点构建二分图,如果i能来得及赶上j的任务,那就连一条i到j'的边,流量为i点所拥有的人数,跑出的最大流即是所能节省下的最大人数,总人数相减即可
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int MAXN = 1000;
const int MAXM = 50010;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to, next, cap, flow;
} edge[MAXM];
int tol;
int head[MAXN];
int gap[MAXN], dep[MAXN], cur[MAXN];
void init()
{
tol = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w, int rw = 0)
{
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].flow = 0;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;
edge[tol].flow = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
int Q[MAXN];
void BFS(int start, int end)
{
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
gap[0] = 1;
int front = 0, rear = 0;
dep[end] = 0;
Q[rear++] = end;
while (front != rear)
{
int u = Q[front++];
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (dep[v] != -1)continue;
Q[rear++] = v;
dep[v] = dep[u] + 1;
gap[dep[v]]++;
}
}
}
int S[MAXN];
int sap(int start, int end, int N)
{
BFS(start, end);
memcpy(cur, head, sizeof(head));
int top = 0;
int u = start;
int ans = 0;
while (dep[start] < N)
{
if (u == end)
{
int Min = INF;
int inser;
for (int i = 0; i < top; i++)
if (Min > edge[S[i]].cap - edge[S[i]].flow)
{
Min = edge[S[i]].cap - edge[S[i]].flow;
inser = i;
}
for (int i = 0; i < top; i++)
{
edge[S[i]].flow += Min;
edge[S[i] ^ 1].flow -= Min;
}
ans += Min;
top = inser;
u = edge[S[top] ^ 1].to;
continue;
}
bool flag = false;
int v;
for (int i = cur[u]; i != -1; i = edge[i].next)
{
v = edge[i].to;
if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])
{
flag = true;
cur[u] = i;
break;
}
}
if (flag)
{
S[top++] = cur[u];
u = v;
continue;
}
int Min = N;
for (int i = head[u]; i != -1; i = edge[i].next)
if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
{
Min = dep[edge[i].to];
cur[u] = i;
}
gap[dep[u]]--;
if (!gap[dep[u]])return ans;
dep[u] = Min + 1;
gap[dep[u]]++;
if (u != start)u = edge[S[--top] ^ 1].to;
}
return ans;
}
typedef long long ll;
int n, m, g[MAXN][MAXN];
ll x[MAXN], y[MAXN], s[MAXN], p[MAXN], t[MAXN];
ll v[MAXN][10];
ll dist(int i, int j)
{
return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
}
int solve(int id)
{
init();
int s = 0, t = 2 * n + 1;
for (int i = 1; i <= n; i++)
{
addedge(s, i, v[i][id]);
addedge(i + n, t, v[i][id]);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (g[i][j])
addedge(i, j + n, v[i][id]);
return sap(s, t, t + 1);
}
int main()
{
int tt;
cin >> tt;
while (tt--)
{
ll sum = 0;
cin >> n >> m;
cin >> x[0] >> y[0];
n--;
for (int i = 1; i <= n; i++)
{
cin >> x[i] >> y[i] >> s[i] >> p[i];
t[i] = s[i] + p[i];
for (int j = 1; j <= m; j++)
{
cin >> v[i][j];
sum += v[i][j];
}
}
memset(g, 0, sizeof(g));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
if (i == j) continue;
if (t[i] <= s[j] && dist(i, j) <= (s[j] - t[i]) * (s[j] - t[i]))
g[i][j] = 1;
}
/* for(int i = 1; i <= n; i++)
{for(int j = 1; j <= n; j++)
printf("%d ", g[i][j]);
printf("\n");
}*/
ll ans = 0;
for (int i = 1; i <= m; i++)
ans += solve(i);
cout << sum - ans << endl;
}
return 0;
}
最小费用流:仍是每个点拆成两个,原有的点代表自身任务,然后源点向这些点连一条流量为该点所需人数费用为1的边,这些点再向汇点连边,新拆出的点用来为其他点提供人数,流量为该点人数,费用为0
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int MAXN = 1000;
const int MAXM = 50000;
const int INF = 0x3f3f3f3f;
typedef long long ll;
struct Edge
{
int to, next, cap, flow, cost;
} edge[MAXM];
int head[MAXN], tol;
int pre[MAXN], dis[MAXN];
bool vis[MAXN];
int N;//节点总个数,节点编号从0~N-1
void init(int n)
{
N = n;
tol = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
edge[tol].to = v;
edge[tol].cap = cap;
edge[tol].cost = cost;
edge[tol].flow = 0;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = 0;
edge[tol].cost = -cost;
edge[tol].flow = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
bool spfa(int s, int t)
{
queue<int>q;
for (int i = 0; i < N; i++)
{
dis[i] = INF;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].cap > edge[i].flow &&
dis[v] > dis[u] + edge[i].cost )
{
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if (!vis[v])
{
vis[v] = true;
q.push(v);
}
}
}
}
if (pre[t] == -1) return false;
else return true;
}
//返回的是最大流,cost存的是最小费用
int minCostMaxflow(int s, int t, int &cost)
{
int flow = 0;
cost = 0;
while (spfa(s, t))
{
int Min = INF;
for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])
{
if (Min > edge[i].cap - edge[i].flow)
Min = edge[i].cap - edge[i].flow;
}
for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])
{
edge[i].flow += Min;
edge[i ^ 1].flow -= Min;
cost += edge[i].cost * Min;
}
flow += Min;
}
return flow;
}
int n, m, g[MAXN][MAXN];
ll x[MAXN], y[MAXN], s[MAXN], p[MAXN], t[MAXN];
ll v[MAXN][10];
ll dist(int i, int j)
{
return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
}
int solve(int id)
{
int s = 0, t = 2 * n + 1;
init(t + 1);
for (int i = 1; i <= n; i++)
{
addedge(s, i, v[i][id], 1);
addedge(s, i + n, v[i][id], 0);
addedge(i, t, v[i][id], 0);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (g[i][j])
addedge(i + n, j, v[i][id], 0);
// for (int i = 0; i < tol; i++)
// printf("%d %d %d\n", edge[i].to, edge[i].cap, edge[i].cost);
int cost;
minCostMaxflow(s, t, cost);
return cost;
}
int main()
{
int tt;
cin >> tt;
while (tt--)
{
cin >> n >> m;
cin >> x[0] >> y[0];
n--;
for (int i = 1; i <= n; i++)
{
cin >> x[i] >> y[i] >> s[i] >> p[i];
t[i] = s[i] + p[i];
for (int j = 1; j <= m; j++)
cin >> v[i][j];
}
memset(g, 0, sizeof(g));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
if(i == j) continue;
if (t[i] <= s[j] && dist(i, j) <= (s[j] - t[i]) * (s[j] - t[i]))
g[i][j] = 1;
}
/* for(int i = 1; i <= n; i++)
{for(int j = 1; j <= n; j++)
printf("%d ", g[i][j]);
printf("\n");
}*/
int ans = 0;
for (int i = 1; i <= m; i++)
ans += solve(i);
cout << ans << endl;
}
return 0;
}