變量(variable)
阿新 • • 發佈:2018-06-10
拆分 討論 ++ abs ini 變量 sin ID DG 或 \(w[x]<w[y]\) 。
, \(n\le 500\) , \(p,q\le 1000\) , \(1\le W\le 10^6\) , \(0\le a_i,b_i,c_i,d_i,e_i,f_i\le 1000\) 。
Description
有 \(n\) 個變量 \(w[1],w[2],\cdots ,w[n]\) ,每個變量可以取 \(W\) 或 \(-W\) 。
有 \(p\) 個式子,形如 \[H_i=a_i\times |w[x_i]-w[y_i]|+b_i\times |w[y_i]-w[z_i]|+c_i\times |w[z_i]-w[x_i]|+d_i\times (w[x_i]-w[y_i])+e_i\times (w[y_i]-w[z_i])+f_i\times (w[z_i]-w[x_i])\]
有 \(q\) 個條件,形如 \(w[x]\le w[y]\) 或 \(w[x]=w[y]\)
最小化 \(\sum w_i+\sum H_i\) 。
Input
第一行一個整數 \(t\) 表示數據組數。
每組數據第一行四個整數 \(n,W,p,q\) 。
接下來 \(p\) 行每行九個整數 \(x_i,y_i,z_i,a_i,b_i,c_i,d_i,e_i,f_i\) 。
接下來 \(q\) 行每行三個整數 \(x,y,r\) 。
\(r=0\) 表示 \(w[x]\le w[y]\) ; \(r=1\) 表示 \(w[x]=w[y]\) ; \(r=2\) 表示 \(w[x]<w[y]\) 。
保證存在方案。
Limit
\(t\le 10\)
Solution
這題看著嚇人而已,不過是套路罷了...
顯然一個變量只有 \(1\) 和 \(-1\) 兩種取值(最後答案乘一個 \(W\) )。
現在將每個變量 \(x\) 看成點。
將 \(x\) 拆分,成為 \(x_1\) 和 \(x_2\) ,表示 \(1\) 和 \(-1\) 兩種取值。
- \((S,x_1)\) 表示 \(x\) 取 \(1\) 。
- \((x_2,T)\) 表示 \(x\) 取 \(2\)
- \((x_1,x_2,+\infty)\) ,表示這條邊不能割,即 \(x\) 不能同時有兩個取值。
- \((x_1,y_2)\) ,流量為二倍,表示絕對值之差為 \(2\) 。
- 對於限制關系,分類討論一些連邊,表示這些邊不能被割。具體見代碼
最小割即可。對於負流量,可以加上一個常數來解決。
#include<bits/stdc++.h>
using namespace std;
template <class T> inline void read(T &x) {
x = 0; static char ch = getchar(); for (; ch < '0' || ch > '9'; ch = getchar());
for (; ch >= '0' && ch <= '9'; ch = getchar()) (x *= 10) += ch - '0';
}
#define N 1050
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define INF 0x3f3f3f3f
#define ll long long
int S, T, head[N], cur[N], tot = 1, q[N], dep[N];
struct edge { int v, c, next; }e[12001];
inline void insert(int u, int v, int c) { e[++tot].v = v, e[tot].c = c, e[tot].next = head[u]; head[u] = tot; }
inline void add(int u, int v, int c) { insert(u, v, c), insert(v, u, 0); }
inline bool bfs() {
memset(dep, 0, sizeof dep); dep[S] = 1;
int l = 1, r = 1; q[1] = S;
while (l <= r) {
int u = q[l++];
for (int i = head[u], v; i; i = e[i].next) if (e[i].c && !dep[v = e[i].v]) {
dep[v] = dep[u] + 1, q[++r] = v;
if (!(v ^ T)) return 1;
}
}
return 0;
}
int dfs(int u, int dist) {
if (u == T) return dist;
int ret = 0;
for (int &i = head[u], v; i; i = e[i].next) if (dep[v = e[i].v] == dep[u] + 1 && e[i].c) {
int d = dfs(v, min(dist - ret, e[i].c));
e[i].c -= d, e[i ^ 1].c += d, ret += d;
if (ret == dist) return dist;
}
if (!ret) dep[u] = -1;
return ret;
}
inline void cpy() { rep(i, S, T) cur[i] = head[i]; }
inline void rec() { rep(i, S, T) head[i] = cur[i]; }
int dinic() { int ret = 0; cpy(); while (bfs()) ret += dfs(S, INF), rec(); return ret; }
int n, p, Q, val[N], g[N][N];
ll W;
int main() {
int Case; read(Case);
while (Case--) {
memset(head, 0, sizeof head); tot = 1;
memset(val, 0, sizeof val), memset(g, 0, sizeof g);
read(n), read(W), read(p), read(Q);
rep(i, 1, n) val[i] = 1;
while (p--) {
int x, y, z, a, b, c, d, e, f;
read(x), read(y), read(z), read(a), read(b), read(c), read(d), read(e), read(f);
val[x] += d - f, val[y] += e - d, val[z] += f - e;
if (x < y) g[x][y] += a; else g[y][x] += a;
if (y < z) g[y][z] += b; else g[z][y] += b;
if (z < x) g[z][x] += c; else g[x][z] += c;
}
int mx = 0; rep(i, 1, n) mx = max(mx, abs(val[i]) + 1);
T = (n << 1) + 1;
rep(i, 1, n) add(S, i, mx + val[i]), add(i, i + n, INF), add(i + n, T, mx - val[i]);
rep(i, 1, n) rep(j, i + 1, n) if (g[i][j]) add(i + n, j, g[i][j] << 1), add(j + n, i, g[i][j] << 1);
while (Q--) {
int x, y, r; read(x), read(y), read(r);
if (!r) add(y + n, x, INF);
if (r == 1) add(x + n, y, INF), add(y + n, x, INF);
if (r == 2) add(S, x, INF), add(y + n, T, INF);
}
printf("%lld\n", (dinic() - mx * n) * W);
}
return 0;
}
變量(variable)