P3652 csh和zzy的战争
给定一些货源地,一些中转岛,以及一个终点。
货源地分为两种,普通货和特殊货。
对于中转岛 ,最多可以中转 件货物,中转岛发向另一个中转岛或军事基地的货物分别不能超过 。
上面货物皆指普通货物,特殊货物不会受到限制。
中转岛之间有 条航道,航道 有边权,开辟航线 的代价是 和 之间的最短路。
最后全局的代价是航线代价的最大值。
要求在所有货物都能够到达军事基地的前提下,最小代价是多少。
std
首先考虑二分最小代价 ,将代价 的航线加入图中,判断是否能将所有货物都送达军事基地即可。
然后考虑特殊货物,只需要先用 dij
求出每个特殊货源地到终点的最短路,然后二分下界即是每个特殊货源地到终点的最短路的最大值。
再考虑普通货物,先 求出两点之间最短路,然后建图跑网络流即可。
。
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
inline void write(int x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
typedef int tp;
const int _ = 5e5 + 10, inf = 1e9 + 7;
int n, m, s, t, lv[_], cur[_];
int tot = 1, head[_], to[_ << 1], nxt[_ << 1];
tp w[_ << 1];
inline void add(int u, int v, tp lv)
{
to[++tot] = v;
nxt[tot] = head[u];
w[tot] = lv;
head[u] = tot;
}
inline void Add(int u, int v, tp lv)
{
add(u, v, lv);
add(v, u, 0);
}
inline bool bfs()
{
memset(lv, -1, sizeof(lv));
lv[s] = 0;
memcpy(cur, head, sizeof(head));
queue<int> q;
q.push(s);
while (!q.empty())
{
int p = q.front();
q.pop();
for (int eg = head[p]; eg; eg = nxt[eg])
{
int v = to[eg];
tp vol = w[eg];
if (vol > 0 && lv[v] == -1)
lv[v] = lv[p] + 1, q.push(v);
}
}
return lv[t] != -1;
}
tp dfs(int p = s, tp flow = inf)
{
if (p == t)
return flow;
tp rmn = flow;
for (int eg = cur[p]; eg && rmn; eg = nxt[eg])
{
cur[p] = eg;
int v = to[eg];
tp vol = w[eg];
if (vol > 0 && lv[v] == lv[p] + 1)
{
tp c = dfs(v, min(vol, rmn));
rmn -= c;
w[eg] -= c;
w[eg ^ 1] += c;
}
}
return flow - rmn;
}
inline tp dinic()
{
tp ans = 0;
while (bfs())
ans += dfs();
return ans;
}
struct node
{
int u, v, w;
} ed[_];
bool cmp(node a, node b)
{
return a.w < b.w;
}
int X, E, M, a[_], ww[_], b[_], d[_], dis[_], mp[507][507];
vector<int> g[307];
bool check(int lit)
{
tot = 1;
memset(head, 0, sizeof head);
int sum = 0;
for (int i = 1; i <= n; i++)
Add(s, i, a[i]), sum += a[i];
for (int i = 1; i <= m; i++)
{
if (b[i])
Add(i + n + m, t, d[i]);
Add(i + n, i + n + m, ww[i]);
for (auto j : g[i])
if (j <= n)
Add(j, i + n, inf);
}
for (int i = 1; i <= M && ed[i].w <= lit; i++)
{
Add(ed[i].u + n + m, ed[i].v + n, d[ed[i].u]);
Add(ed[i].v + n + m, ed[i].u + n, d[ed[i].v]);
}
return !(sum - dinic());
}
struct abc
{
int u, val;
bool operator < (const abc tmp) const
{
return tmp.val < val;
}
};
void dij(int u)
{
priority_queue<abc> q;
q.push({u, 0});
for(int i = 0; i < _; ++i) dis[i] = inf, lv[i] = 0;
dis[u] = 0;
while(!q.empty())
{
abc tmp = q.top();
int now = tmp.u;
q.pop();
if(lv[now]) continue;
lv[now] = 1;
for(int i = head[now]; i; i = nxt[i])
{
int v = to[i];
if(dis[v] > dis[now] + w[i])
{
dis[v] = dis[now] + w[i];
if(!lv[v]) q.push({v, dis[v]});
}
}
}
}
signed main()
{
int x, y, z;
n = read(), m = read(), X = read(), E = read();
for (int i = 1; i <= n + X; i++)
a[i] = read();
for (int i = 1; i <= m; i++)
ww[i] = read();
for (int i = 1; i <= m; i++)
d[i] = read();
for (int i = 1; i <= m; i++)
{
x = read();
for (int j = 1; j <= x; j++)
{
y = read();
g[i].push_back(y);
add(n + X + i, y, 0);
}
b[i] = read();
if (b[i])
add(n + X + m + 1, n + X + i, 0);
}
for (int i = 1; i <= E; i++)
{
x = read(), y = read(), z = read();
mp[x][y] += z, mp[y][x] += z;
}
for (int i = 1; i <= m; i++)
for (int j = 1; j <= m; j++)
if (!mp[i][j])
mp[i][j] = inf;
else if (i != j)
add(n + X + i, n + X + j, mp[i][j]);
for (int k = 1; k <= m; k++)
for (int i = 1; i <= m; i++)
for (int j = 1; j <= m; j++)
mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]);
dij(n + m + X + 1);
s = 0, t = _ - 1;
for (int i = 1; i <= m; i++)
for (int j = i + 1; j <= m; j++)
if (mp[i][j] < inf)
ed[++M] = (node){i, j, mp[i][j]};
sort(ed + 1, ed + M + 1, cmp);
int l = 0, r = inf, mid;
for (int i = n + 1; i <= n + X; i++)
l = max(l, lv[i]);
while (l <= r)
{
mid = l + r >> 1;
if (check(mid))
r = mid - 1;
else
l = mid + 1;
}
if (r != inf)
write(r + 1);
else
write(-1);
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122032