题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4940
题意:给出一张有向强连通图,每条边有两个权值分别是破坏该边的权值和修建双向边的权值(修建前要先破坏),对于一个集合S和S的补集T,破坏所有从S到T的边的权值和为X,修建T到S的双向边的权值和为Y,问是否存在某一集合满足 Y < X
思路:考虑这两个集合,从S集合流出的流量能通过其他边流回,倘若对于所有流出去的流量最后都能流回来则证明始终有X <= Y,对于每条有向边而言其流量下界为D,上界为D + B,对任一集合S必有流量守恒,流入的总流量为Y,流出的总流量为X,倘若能满流则必有X <= Y,建图方法可以参照《一种简易的方法求解流量有上下界的网络中网络流问题》
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long ll;
const int MAXN = 1000;
const int MAXM = 100010;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to, next, cap, flow;
} edge[MAXM];
int tol;
int Head[MAXN];
int gap[MAXN], dep[MAXN], cur[MAXN];
void init()
{
tol = 0;
memset(Head, -1, sizeof(Head));
}
void addedge(int u, int v, int w, int rw = 0)
{
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].flow = 0;
edge[tol].next = Head[u];
Head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;
edge[tol].flow = 0;
edge[tol].next = Head[v];
Head[v] = tol++;
}
int Q[MAXN];
void BFS(int start, int end)
{
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
gap[0] = 1;
int front = 0, rear = 0;
dep[end] = 0;
Q[rear++] = end;
while (front != rear)
{
int u = Q[front++];
for (int i = Head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (dep[v] != -1)continue;
Q[rear++] = v;
dep[v] = dep[u] + 1;
gap[dep[v]]++;
}
}
}
int S[MAXN];
int sap(int start, int end, int N)
{
BFS(start, end);
memcpy(cur, Head, sizeof(Head));
int top = 0;
int u = start;
int ans = 0;
while (dep[start] < N)
{
if (u == end)
{
int Min = INF;
int inser;
for (int i = 0; i < top; i++)
if (Min > edge[S[i]].cap - edge[S[i]].flow)
{
Min = edge[S[i]].cap - edge[S[i]].flow;
inser = i;
}
for (int i = 0; i < top; i++)
{
edge[S[i]].flow += Min;
edge[S[i] ^ 1].flow -= Min;
}
ans += Min;
top = inser;
u = edge[S[top] ^ 1].to;
continue;
}
bool flag = false;
int v;
for (int i = cur[u]; i != -1; i = edge[i].next)
{
v = edge[i].to;
if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])
{
flag = true;
cur[u] = i;
break;
}
}
if (flag)
{
S[top++] = cur[u];
u = v;
continue;
}
int Min = N;
for (int i = Head[u]; i != -1; i = edge[i].next)
if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
{
Min = dep[edge[i].to];
cur[u] = i;
}
gap[dep[u]]--;
if (!gap[dep[u]])return ans;
dep[u] = Min + 1;
gap[dep[u]]++;
if (u != start)u = edge[S[--top] ^ 1].to;
}
return ans;
}
int w[MAXN];
int main()
{
int t;
cin >> t;
for (int ca = 1; ca <= t; ca++)
{
int n, m;
cin >> n >> m;
init();
memset(w, 0, sizeof(w));
int s = 0, t = n + 1;
for (int i = 0; i < m; i++)
{
int u, v, d, b;
scanf("%d%d%d%d", &u, &v, &d, &b);
addedge(u, v, b);
w[v] += d;
w[u] -= d;
}
int sum = 0;
for (int i = 1; i <= n; i++)
{
if (w[i] > 0)
{
sum += w[i];
addedge(s, i, w[i]);
}
if (w[i] < 0)
{
addedge(i, t, -w[i]);
}
}
int flow = sap(s, t, t + 1);
if (sum == flow)
printf("Case #%d: happy\n", ca);
else
printf("Case #%d: unhappy\n", ca);
}
return 0;
}