POJ 3498【最大流+拆點建圖】
阿新 • • 發佈:2018-05-01
code 集合 mem str ring con 我們 距離 fine
題意: 在X,Y坐標系中有N(N<=100)個冰塊...有些冰塊上有若幹只企鵝..每只企鵝一次最多跳M距離..一個冰塊在有Mi個企鵝離開..就會消失..問有哪些冰塊可以作為集合點..就是所有企鵝都能成功到這個冰塊上來.
這個題建圖比較有意思。
把每塊冰分成兩個點i和i+n. i表示進入i冰塊的點(可以有無數企鵝過來,所以從別的冰到i有邊,容量為INF) i+n表示從i冰塊出去的點(最多只能有Mi企鵝從這跳出去,所以從i到i+n有邊,且容量為Mi)
從源點S到i有邊(S, i, i點初始企鵝數).
從i到i+n有邊(i, i+n, Mi). 表示第i塊冰最多只有Mi個企鵝能跳走.
因為i+n表示的是第i個跳走的點,所以如果冰塊i和j之間的距離<=企鵝能跳躍的距離M,有邊(i+n, j, INF)假設我們當前枚舉第x塊冰塊作為集合點,那麽(x分成x和x+n兩個點)x點就是匯點(不是x+n點哦),我們只要計算到x點的流量是否==企鵝總數即可.
#include<stdio.h> #include<string.h> #include<queue> #include<cmath> #define maxn 1000 #define INF 0x3f3f3f3f using namespace std; struct e { int from, to, w, next; }edge[1000000]; struct p { int x, y; }pos[10000]; int ss, tt; int n; double d; int cur[maxn]; int cont; int head[maxn]; int map[maxn][maxn]; int dis[maxn][maxn]; int divv[maxn]; int x[maxn], y[maxn], num[maxn], m[maxn]; bool check(p a, p b) { double dis = sqrt(pow(fabs(a.x - b.x), 2) + pow(fabs(a.y - b.y), 2)); if (dis <= d) return true; else return false; } void add(int u, int v, int w) { edge[cont].from = u; edge[cont].to = v; edge[cont].w = w; edge[cont].next = head[u]; head[u] = cont++; } void makediv() { memset(divv, 0, sizeof(divv)); divv[ss] = 1; queue<int> Q; Q.push(ss); while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = head[u]; i != -1; i = edge[i].next) { int w = edge[i].w; int v = edge[i].to; if (divv[v] == 0 && w) { divv[v] = divv[u] + 1; Q.push(v); } } } } int DFS(int u, int maxflow, int tt) { if (u == tt) return maxflow; int ret = 0; for (int &i = cur[u]; i != -1; i = edge[i].next) { int v = edge[i].to; int w = edge[i].w; if (divv[v] == divv[u] + 1 && w) { int f = DFS(v, min(maxflow - ret, w), tt); edge[i].w -= f; edge[i ^ 1].w += f; ret += f; if (ret == maxflow) return ret; } } return ret; } int Dinic() { int ans = 0; while (1) { makediv(); if (divv[tt] == 0) break; memcpy(cur, head, sizeof(head)); ans += DFS(ss, INF, tt); } return ans; } void Build() { for (int i = 1; i <= n; i++) { add(ss, i, num[i]); add(i, ss, 0); add(i, i + n, m[i]); add(i + n, i, 0); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (i == j) continue; if (check(pos[i], pos[j])) { add(i + n, j, INF); add(j, i + n, 0); } } } } int main(void) { int t; int p_n; scanf("%d", &t); while (t--) { bool flag = false; ss = 0; p_n = 0; scanf("%d%lf", &n, &d); memset(head, -1, sizeof(head)); for (int i = 1; i <= n; i++) { scanf("%d%d%d%d", &x[i], &y[i], &num[i], &m[i]); if (num) p_n += num[i]; pos[i].x = x[i]; pos[i].y = y[i]; } vector<int> V; for (int i = 1; i <= n; i++) { tt = i; cont = 0; memset(head, -1, sizeof(head)); Build(); if (Dinic() == p_n) { flag = true; V.push_back(i - 1); } } if (!flag) printf("-1\n"); else { for (int i = 0; i < (int)V.size(); i++) if (i != V.size() - 1) printf("%d ", V[i]); else printf("%d\n", V[i]); } } return 0; }
POJ 3498【最大流+拆點建圖】