给你一个强连通图,然后问你是否可以找到任意满足条件的集合S,S是非空集合,T是S的补集,满足sum(D[i ,j]) <= sum(D[j,i] + B[j,i]) i属于S集合,j属于T集合(其实也就暗示了i,j是S,T的割边)。
思路:
无源汇上下流可行流判断问题,首先题目给的图是一个强连通图,为了方便理解,我们假设这个图只有两个点,a,b,那么肯定也只有两条边,a->b ,b->a,那么我们可以直接建边a->b(下界 D 上界 B + D) b->a(下界 D 上界 B + D)这样跑一遍上下流之后如果存在可行流,那么就存在一个a,b之间的循环流(循环流的大小我们不用关心,我们只关心是否存在),那么就会有这样的结论,a->b的D(下限)一定小于等于b->a 的D+B(上限),同时 b->a的D(下限) 一定小于等于a->b的 D+B(上限),所以无论是a,还是b都可以充当S集合。so如果整个图中任意两个集合都这样就显然可以满足题意了。
#include<stdio.h> #include<string.h> #include<queue> #define N_node 220 #define N_edge 33000 #define INF 1000000000 using namespace std; typedef struct { int to ,next ,cost; }STAR; typedef struct { int x ,t; }DEP; STAR E[N_edge]; DEP xin ,tou; int list[N_node] ,listt[N_node] ,tot; int deep[N_node] ,sum_must; void add(int a ,int b ,int c) { E[++tot].to = b; E[tot].cost = c; E[tot].next = list[a]; list[a] = tot; E[++tot].to = a; E[tot].cost = 0; E[tot].next = list[b]; list[b] = tot; } void ADD(int a ,int b ,int c ,int d ,int ss ,int tt) { add(a ,b ,d - c); add(a ,tt ,c); add(ss ,b ,c); sum_must += c; } int minn(int x ,int y) { return x < y ? x : y; } bool BFS_Deep(int s ,int t ,int n) { xin.x = s ,xin.t = 0; queue<DEP>q; q.push(xin); memset(deep ,255 ,sizeof(deep)); deep[s] = 0; while(!q.empty()) { tou = q.front(); q.pop(); for(int k = list[tou.x] ;k ;k = E[k].next) { xin.x = E[k].to; xin.t = tou.t + 1; if(deep[xin.x] != -1 || !E[k].cost) continue; deep[xin.x] = xin.t; q.push(xin); } } for(int i = 0 ;i <= n ;i ++) listt[i] = list[i]; return deep[t] != -1; } int DFS_Flow(int s ,int t ,int flow) { if(s == t) return flow; int nowflow = 0; for(int k = listt[s] ;k ;k = E[k].next) { listt[s] = k; int to = E[k].to; int c = E[k].cost; if(deep[to] != deep[s] + 1 || !c) continue; int tmp = DFS_Flow(to ,t ,minn(c ,flow - nowflow)); nowflow += tmp; E[k].cost -= tmp; E[k^1].cost += tmp; if(nowflow == flow) break; } if(!nowflow) deep[s] = 0; return nowflow; } int DINIC(int s ,int t ,int n) { int ans = 0; while(BFS_Deep(s ,t ,n)) { ans += DFS_Flow(s ,t ,INF); } return ans; } int main () { int t ,n ,m ,i ,a ,b ,c ,d ,cas = 1; scanf("%d" ,&t); while(t--) { scanf("%d %d" ,&n ,&m); int ss = 0 ,tt = n + 1; memset(list ,0 ,sizeof(list)); tot = 1 ,sum_must = 0; for(i = 1 ;i <= m ;i ++) { scanf("%d %d %d %d" ,&a ,&b ,&c ,&d); ADD(a ,b ,c ,c + d ,ss ,tt); } printf("Case #%d: " ,cas ++); sum_must == DINIC(ss ,tt ,tt) ? puts("happy") : puts("unhappy"); } return 0; }