源汇不确定时还原现场
有时候最大流问题需要我们枚举源点和汇点
此时每次枚举完毕的时候,要还原现场
-
对于边 $e \in E[\cdots \text{idx}]$,$e[i]$ 的流量 $|f|$ 为 $e[i \oplus 1]$ 的容量 $|c|$
-
$\text{dinic}$ 算法维护的是残量网络 $G_f$,最开始流量为 $0$
所以还原现场 $2$ 步即可,注意残量网络中 $e = c(u, v)$,边维护的是容量
对于所有的边 $\textbf{for} \ \forall e_i \in E[\cdots \text{idx}]$
-
反向边容量退流,$e[i] \leftarrow e[i] + e[i \oplus 1]$
-
正向边流量清空,正向边流量等于反向边容量,所以 $e[i \oplus 1] \leftarrow 0$
-
对于冰块 $u$,它的每一条出边 $i$,必须满足 $\sum e_i \leqslant m_u$
很自然地想到拆点,$u \to (u_1, u_2), \quad e(u_1, u_2) = m_u$ -
冰块 $(u, v)$ 之间能够互相跳到,充要条件是 $\text{dist}(u, v) \leqslant D$
由于 $(u, v)$ 这条路径上可以允许无数企鹅经过
(注意,对起跳终点 $v$ 并没有限制,对起点的限制已经加在拆点上了)
添加边 $c(u, v) = \infty, \ c(v, u) = \infty, \quad u, v$ 是拆点后的 -
考虑源点,对于所有有企鹅的冰块,$\textbf{for} \ \forall i, \quad n_i > 0$:
$c(S, i) = n_i$ -
枚举每一个汇点 $T \in [1 \cdots n]$,枚举前记得还原现场,如果
$\textbf{dinic}(S, T) = tot, \quad res ++$
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <bitset>
#include <assert.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
#define Cmp(a, b) memcmp(a, b, sizeof(b))
#define Cpy(a, b) memcpy(a, b, sizeof(b))
#define Set(a, v) memset(a, v, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define _forS(i, l, r) for(set<int>::iterator i = (l); i != (r); i++)
#define _rep(i, l, r) for(int i = (l); i <= (r); i++)
#define _for(i, l, r) for(int i = (l); i < (r); i++)
#define _forDown(i, l, r) for(int i = (l); i >= r; i--)
#define debug_(ch, i) printf(#ch"[%d]: %d\n", i, ch[i])
#define debug_m(mp, p) printf(#mp"[%d]: %d\n", p->first, p->second)
#define debugS(str) cout << "dbg: " << str << endl;
#define debugArr(arr, x, y) _for(i, 0, x) { _for(j, 0, y) printf("%c", arr[i][j]); printf("\n"); }
#define _forPlus(i, l, d, r) for(int i = (l); i + d < (r); i++)
#define lowbit(i) (i & (-i))
#define MPR(a, b) make_pair(a, b)
pair<int, int> crack(int n) {
int st = sqrt(n);
int fac = n / st;
while (n % st) {
st += 1;
fac = n / st;
}
return make_pair(st, fac);
}
inline ll qpow(ll a, int n) {
ll ans = 1;
for(; n; n >>= 1) {
if(n & 1) ans *= 1ll * a;
a *= a;
}
return ans;
}
template <class T>
inline bool chmax(T& a, T b) {
if(a < b) {
a = b;
return true;
}
return false;
}
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll ksc(ll a, ll b, ll mod) {
ll ans = 0;
for(; b; b >>= 1) {
if (b & 1) ans = (ans + a) % mod;
a = (a * 2) % mod;
}
return ans;
}
ll ksm(ll a, ll b, ll mod) {
ll ans = 1 % mod;
a %= mod;
for(; b; b >>= 1) {
if (b & 1) ans = ksc(ans, a, mod);
a = ksc(a, a, mod);
}
return ans;
}
template <class T>
inline bool chmin(T& a, T b) {
if(a > b) {
a = b;
return true;
}
return false;
}
template<class T>
bool lexSmaller(vector<T> a, vector<T> b) {
int n = a.size(), m = b.size();
int i;
for(i = 0; i < n && i < m; i++) {
if (a[i] < b[i]) return true;
else if (b[i] < a[i]) return false;
}
return (i == n && i < m);
}
// ============================================================== //
typedef pair<int, int> PII;
const int maxn = 210, maxm = (210 + 210 + 210*210) * 2;
const int inf = 0x3f3f3f3f;
const double eps = 1e-5;
int head[maxn], ver[maxm], e[maxm], ne[maxm], idx = 1;
int n, S = 0, T, tot = 0;
double D;
PII ice[maxn];
void add(int a, int b, int c) {
ver[++idx] = b; e[idx] = c; ne[idx] = head[a]; head[a] = idx;
ver[++idx] = a; e[idx] = 0; ne[idx] = head[b]; head[b] = idx;
}
bool check(const PII &a, const PII &b) {
double dx = a.first - b.first, dy = a.second - b.second;
return dx*dx + dy*dy <= D*D + eps;
}
void init() {
memset(head, 0, sizeof head);
idx = 1;
tot = 0;
}
int d[maxn], cur[maxn];
bool bfs() {
memset(d, -1, sizeof d);
d[S] = 0, cur[S] = head[S];
queue<int> q; q.push(S);
while (q.size()) {
int x = q.front(); q.pop();
for (int i = head[x]; i; i = ne[i]) {
int y = ver[i];
if (d[y] == -1 && e[i]) {
d[y] = d[x] + 1;
cur[y] = head[y];
if (y == T) return true;
q.push(y);
}
}
}
return false;
}
int dinic(int u, int lim) {
if (u == T) return lim;
int flow = 0;
for (int i = cur[u]; i && lim > flow; i = ne[i]) {
cur[u] = i;
int v = ver[i];
if (d[v] == d[u] + 1 && e[i]) {
int t = dinic(v, min(e[i], lim - flow));
if (!t) d[v] = -1;
flow += t, e[i] -= t, e[i^1] += t;
}
}
return flow;
}
int dinic() {
int res = 0, flow;
while (bfs()) while (flow = dinic(S, inf)) res += flow;
return res;
}
void solve() {
int cnt = 0;
for (int i = 1; i <= n; i++) {
T = i;
for (int k = 2; k <= idx; k += 2) {
e[k] += e[k^1];
e[k^1] = 0;
}
int res = dinic();
if (res == tot) {
cnt++;
printf("%d ", i-1);
}
}
if (cnt == 0) printf("-1\n");
else printf("\n");
}
int main() {
freopen("input.txt", "r", stdin);
int kase;
cin >> kase;
while (kase--) {
init();
scanf("%d%lf", &n, &D);
S = 0;
// ice
for (int i = 1; i <= n; i++) {
int x, y, _n, _m;
scanf("%d%d%d%d", &x, &y, &_n, &_m);
ice[i] = {x, y};
add(i, n+i, _m);
add(S, i, _n);
tot += _n;
}
// link node
for (int i = 1; i <= n; i++) for (int j = i+1; j <= n; j++) {
if (check(ice[i], ice[j])) {
add(n+i, j, inf);
add(n+j, i, inf);
}
}
// then solve
solve();
}
}