题意:有n个点和m条又向边,给你的原图是强连通,每一条边有两个边权B,D,其中D代表删除一条边的代价,B代表在u,v之间把有向边转化成无向边的代价。现在将n个点分成两个点集S,T,其中S和T互补(点k要么属于S,要么属于T),现在定义一个,表示所有横跨两集合(S->T)的边的D权值和。
,表示(T->S)的边的D+B权值和。现在问是否对于任意的集合S,T总有Y>=X,如果有输出happy,否则输出unhappy。
想法:首先看Y>=X,只要Y==X恒成立,由于给我们的图是强连通,显然,每一个点,都有出边也有进边,显然出边加的是X的值,入边加的是Y的值,现在要使得X==Y,那么就是要让每一个点的入流和出流想等,那么就要求解此无源汇有上下界的网络流是否有可行流。
建图:虚拟超级源点汇点ss,tt。
计算出每一个点的du[i]=所有入流-所有出流
如果du[i]>0, add(ss,i,du[i]);
如果du[i]<=0, add(i,tt,-du[i]);
判断可行:算ss,tt到,最大流,如果每条边都是满流,那么存在可行流。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define inf 0x7fffffff
using namespace std;
const int N=550;
const int M=50000;
int n,m,ss,tt;
struct node
{
int v,next,flows;
}e[M];
int head[N],cnt,du[N];
void Init()
{
memset (head,-1,sizeof(head));
memset (du,0,sizeof(du));
cnt=0;
}
void add(int a,int b,int c)
{
e[cnt].v = b;
e[cnt].flows = c;
e[cnt].next = head[a];
head[a] = cnt++;
e[cnt].v = a;
e[cnt].flows = 0;
e[cnt].next = head[b];
head[b] = cnt++;
}
class Dinic
{
public:
bool spath()
{
queue <int> q;
while(!q.empty()) q.pop();
memset(dis,-1,sizeof(dis));
dis[ss] = 0;
q.push(ss);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = head[u]; i+1 ;i = e[i].next)
{
int v = e[i].v;
if(dis[v] == -1&& e[i].flows>0)
{
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
return dis[tt] != -1;
}
int Min(int a ,int b)
{
if(a > b) return b;
return a;
}
int dfs(int u,int flows)
{
int cost = 0;
if(u==tt) return flows;
for(int i = head[u]; i+1 ;i = e[i].next)
{
int v = e[i].v;
if(dis[v] == dis[u] + 1&& e[i].flows>0)
{
int minn=dfs( v,Min(flows-cost, e[i].flows));
if(minn>0)
{
e[i].flows -= minn;
e[i^1].flows += minn;
cost += minn;
if(cost == flows) break;
}
else dis[v] = -1;
}
}
return cost ;
}
int result()
{
int res = 0;
while(spath())
{
res += dfs(ss,inf);
}
return res ;
}
private:
int dis[N];
}dinic;
int main()
{
int t,ca=1;
scanf("%d",&t);
while(t--)
{
int sumflows=0;
scanf("%d%d",&n,&m);
Init();
ss=0;tt=n+1;
for(int i=1;i<=m;i++)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
add(a,b,d);
du[a]-=c;
du[b]+=c;
}
for(int i=1;i<=n;i++)
{
if(du[i]>0)
{
sumflows+=du[i];
add(ss,i,du[i]);
}
else
{
add(i,tt,-du[i]);
}
}
int flows=dinic.result();
printf("Case #%d: ",ca++);
if (sumflows == flows)
{
puts ("happy");
}
else puts ("unhappy");
}
return 0 ;
}