对于 10 0% 的数据: 2 ≤ N ≤ 400, 1 ≤ M ≤ 4 00 0,1 ≤ T ≤ 5,1 ≤ Ai, c ≤ 10^9。无向图可能 有重边 。
首先建出最短路图,显然第二问就是跑个最小割吗?
第一问相当于问是否有大于一个最小割。
先跑一遍最大流,残量网络就分为三个部分:
1.超级源S能够走到的点。
2.能够走到超级汇T的点。
3.不属于以上两种的。
不显然结论:
若有条边(u,v),u、v分属于1、2部分,则(u,v)一定是任意一组最小割的割边。
这个证明非常简单。
假设(u,v)不能删,即给它的流量赋个inf。
那么现在S和T连通了。
我们必须要找到一条S->u的增广路或是v->T的增广路。
这个流量是不可能小于当前(u,v)的流量的,不然的话,一开始割的就是不是(u,v)了。
至此得证。
注意这题的坑点在于要拆点建图。
因为若有a[u]=a[v],且(u,v)是割集的一条边,其实是有两种割法的。
拆点就可以判掉了。
Code:
#include
#include
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int N = 100005;
int Q, n, m, x, y, z;
int final[N], to[N], next[N], w[N], tot;
ll a[N];
void link(int x, int y, int z) {
next[++ tot] = final[x], to[tot] = y, w[tot] = z, final[x] = tot;
next[++ tot] = final[y], to[tot] = x, w[tot] = z, final[y] = tot;
}
int d[N * 100], bz[N], bx[N]; ll dis[N], dis2[N];
void spfa(int s, ll *dis) {
fo(i, 1, n) dis[i] = 1e18;
dis[s] = 0; d[d[0] = 1] = s; bz[s] = 1;
fo(i, 1, d[0]) {
int x = d[i];
for(int j = final[x]; j; j = next[j]) {
int y = to[j];
if(dis[x] + w[j] < dis[y]) {
dis[y] = dis[x] + w[j];
if(!bz[y]) d[++ d[0]] = y, bz[y] = 1;
}
}
bz[x] = 0;
}
}
const int M = 1e6;
int b[405][405];
int S, T, co[M], dt[M], cur[M], tt, ts;
struct edge {
int final[M], next[M], to[M], tot;
ll r[M];
void link(int x, int y, ll z) {
next[++ tot] = final[x], to[tot] = y, r[tot] = z, final[x] = tot;
next[++ tot] = final[y], to[tot] = x, r[tot] = 0, final[y] = tot;
}
void cl() {
fo(i, 1, tt) final[i] = dt[i] = co[i] = cur[i] = 0;
fo(i, 2, tot) next[i] = 0;
tot = 1;
}
} e;
ll dfs(int x, ll flow) {
if(x == T) return flow;
ll use = 0;
for(int i = cur[x]; i; i = e.next[i], cur[x] = i) {
int y = e.to[i];
if(e.r[i] && dt[y] + 1 == dt[x]) {
ll tmp = dfs(y, min(flow - use, e.r[i]));
e.r[i] -= tmp, e.r[i ^ 1] += tmp, use += tmp;
if(use == flow) return use;
}
}
cur[x] = e.final[x];
if(!(-- co[dt[x]])) dt[S] = tt;
++ co[++ dt[x]];
return use;
}
void dg(int x) {
if(bz[x]) return;
bz[x] = 1;
for(int i = e.final[x]; i; i = e.next[i])
if(e.r[i]) dg(e.to[i]);
}
void dg2(int x) {
if(bz[x]) return;
bz[x] = 2;
for(int i = e.final[x]; i; i = e.next[i])
if(e.r[i ^ 1]) dg2(e.to[i]);
}
int main() {
for(scanf("%d", &Q); Q; Q --) {
fo(i, 1, tot) next[i] = 0;
fo(i, 1, n) final[i] = 0;
tot = 0;
scanf("%d %d", &n, &m);
fo(i, 1, n - 1) scanf("%lld", &a[i]);
a[n] = 1e18;
fo(i, 1, m) {
scanf("%d %d %d", &x, &y, &z);
link(x, y, z);
}
fo(i, 1, n) bz[i] = 0;
spfa(1, dis); spfa(n, dis2);
fo(i, 1, n) bx[i] = (dis[i] + dis2[i] == dis[n]);
fo(i, 1, n) fo(j, 1, n) b[i][j] = 0;
fo(x, 1, n) if(bx[x]) for(int j = final[x]; j; j = next[j])
if(dis[x] + w[j] == dis[to[j]] && bx[to[j]])
b[x][to[j]] ++;
e.cl();
S = 1; T = n; tt = T;
fo(i, 1, n) fo(j, 1, n) if(b[i][j]) {
tt ++;
e.link(i, tt, (ll) b[i][j] * a[i]),
e.link(tt, j, (ll) b[i][j] * a[j]);
}
co[0] = tt; ll ans = 0;
for(; dt[S] < tt;) ans += dfs(S, 1LL << 62);
fo(i, 1, tt) bz[i] = 0;
dg(S); dg2(T);
ll ans2 = 0;
fo(i, 1, tt) for(int j = e.final[i]; j; j = e.next[j])
if(bz[i] && bz[e.to[j]] && bz[i] != bz[e.to[j]])
ans2 += e.r[j];
if(ans == ans2) printf("Yes "); else printf("No ");
printf("%lld\n", ans);
}
}