P4177 [CEOI2008] order
不妨先看一个子问题:太空飞行计划问题,它就是广为人知的“最大权闭合子图”模型。
在这道子问题中,仪器(机器)不能租用。我们考虑一个反悔的过程——开始先把所有实验的贡献算上,之后利用最小割模型去掉最小代价使得方案合法。
在最小割模型中,我们把所有实验、仪器都分别看成一个点。其中,源点向所有实验连一条容量为实验赞助费的边,所有仪器向汇点连一条容量为购买代价的边。对于实验、仪器两者之间的边,只需要把实验连向它所需要的仪器,容量为无穷大(表示中间的边不能割,只能割掉实验的边或者所有相关仪器的边)。
最后求一个最小割就行了。
然而在这道题中,却出现了租用的代价。考虑把工序与机器之间的边权替换成租用的价格——问题迎刃而解。
#include <bits/stdc++.h>
#define FL(i, a, b) for(int i = (a); i <= (b); i++)
#define FR(i, a, b) for(int i = (a); i >= (b); i--)
using namespace std;
typedef long long ll;
const int N = 2410, M = 1442410;
const ll INF = 1e18;
struct E{int v; ll w, nxt;} e[M << 1];
int n, m, s, t, ans, vis[N], a[N], b[N], tote, head[N], now[N], dep[N];
vector<int> id;
void Adde(int u, int v, ll w){
e[tote] = {v, w, head[u]}, head[u] = tote++;
}
int bfs(){
queue<int> q; q.push(s);
memset(dep, 0, sizeof(dep)), dep[s] = 1;
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = now[u] = head[u]; ~i; i = e[i].nxt)
if(e[i].w && !dep[e[i].v])
q.push(e[i].v), dep[e[i].v] = dep[u] + 1;
}
return dep[t];
}
ll dfs(int u, ll in){
if(u == t) return in; ll out = 0;
for(int i = now[u]; ~i && in; i = e[i].nxt){
int v = e[i].v; ll w = e[i].w; now[u] = i;
if(dep[v] == dep[u] + 1 && w){
ll flow = dfs(v, min(in, (ll)w));
in -= flow, out += flow;
e[i].w -= flow, e[i ^ 1].w += flow;
}
}
if(!out) dep[u] = 0; return out;
}
ll dinic(){
ll ret = 0;
while(bfs()) ret += dfs(s, INF);
return ret;
}
int main(){
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &m);
int ti; s = 0; t = n + m + 1;
FL(i, 1, n){
scanf("%d%d", &a[i], &ti), ans += a[i];
Adde(s, i, a[i]), Adde(i, s, 0);
FL(j, 1, ti){
int x, y; scanf("%d%d", &x, &y);
Adde(i, n + x, y), Adde(n + x, i, 0);
}
}
FL(i, 1, m){
scanf("%d", &b[i]);
Adde(n + i, t, b[i]), Adde(t, n + i, 0);
}
ans -= dinic(), printf("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号