HUST 1342 有上下界最小流

Cheat Secretly

Description

HH Big Cow(HBC) has taken part in an interesting treasure finding match. In the match there are N transmitting nodes(labeled from 1 to N), and between these nodes there are M directional roads. In the middle of some roads there may be a “gift-spot”, where a beautiful girl gives a gift to the contestant who passes that road. The one who gets most gifts wins! Winning the match is so easy for HBC, so he is thinking of a more challenging thing —— collecting gifts from ALL the girls. HBC has an amazing ability to achieve this goal: When he comes to a dead end, he can transfer himself to another node arbitrarily. With that ability, of course he can achieve the goal of meeting all the girls, however, cheating is not good! So he decides to use the ability as few as possible. Now he wants to know the fewest times he should use that ability to achieve his goal. NOTE: 1. The graph in the match is a directed acyclic graph (DAG). 2. There is at most one road between any two nodes.

Input

The input contains multiple case. Line 1 an integer T : number of test cases. Line 2 two integer N, M: N for number of nodes. (2 <= N <= 500) M for number of roads. (1 <= M <= 10000) Lines 3..M+2 each line three integers a, b, c: representing a directed roads from a to b. (1 <= a, b <= N) c = 1, then there is a gift spot on this road. c = 0, then there is no gift spot on this road.

Output

For each case output one line representing the fewest number of ability HBC should use.
Sample Input
2

4 2

1 2 1
3 4 1

6 7

1 2 1
2 3 1
3 4 1
1 4 0
5 2 1
3 6 1
5 6 0
Sample Output
Case #1: 2
Case #2: 2

題意:給一個DAG,然後有些邊必須走,這樣的條件下求最少選擇多少路徑使得所有的比走邊都走完。

解法:

  • 根據各個點的入度和出度,首先選起點都是在入度爲0的點,路徑的終點都是出度爲0的點,添加源匯,分別連上。
  • 然後,必走的邊的下限爲1,上限無窮,新建超級源匯,先跑一邊sap,在連接源匯,再跑一遍的結果就是最小流。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
using namespace std ;

const int INF = 0x3f3f3f3f ;
const int N = 511 ;
const int M = 5e4 + 11 ;

struct Edge {
    int next , to ;
    int flow , cap ;
    Edge(){}
    Edge(int a , int b , int c) {
        next = a , to = b , flow = cap = c ;
    }
};

int head[N] ; Edge err[M] ;  int nedge ;
int gap[N] , dis[N] ; int gnode ;
int super_source , super_sink , source , sink , start , dest ;
int n , m ;

void add_edge(int a , int b , int c) {
    if(head[a] == -1) ++gnode ;
    if(head[b] == -1) ++gnode ;
    err[++nedge] = Edge(head[a] , b , c) ; head[a] = nedge ;
    err[++nedge] = Edge(head[b] , a , 0) ; head[b] = nedge ;
}

int tot[N] ;
bool in[N] , out[N] ;
void init() {
    memset(head , -1 , sizeof(head)) ; nedge = -1 ; gnode = 0 ;
    memset(in , 0 , sizeof(in)) ;
    memset(out , 0 , sizeof(out)) ;
    memset(tot , 0 , sizeof(tot)) ;
    int a , b , c ;
    while(m--) {
        scanf("%d%d%d" ,&a ,&b ,&c) ;
        if(c == 0) {
            add_edge(a , b , INF) ;
            in[b] = true ;
            out[a] = true ;
        }else {
            tot[a] -= 1 , tot[b] += 1 ;
            add_edge(a , b , INF) ;
        }
    }
    source = 0 , sink = n+1 ;
    super_source = n+2 , super_sink = n+3 ;
    for(int i = 1 ; i <= n ; ++i) {
        if(out[i] == false) add_edge(i , sink , INF) ;
        if(in[i] == false) add_edge(source , i , INF) ;
        if(tot[i] > 0) {
            add_edge(super_source , i , tot[i]) ;
        }else if(tot[i] < 0) {
            add_edge(i , super_sink , -tot[i]) ;
        }
    }
}

int dfs(int u , int limit) {
    if(u == dest) return limit ;
    int f1 = 0 , f ;
    int minh = gnode-1 ;
    for(int i = head[u] ; i != -1 ;i  = err[i].next) {
        int v = err[i].to ;
        if(err[i].flow > 0) {
            if(dis[v]+1 == dis[u]) {
                f = dfs(v , min(limit , err[i].flow)) ;
                err[i].flow -= f ;
                err[i^1].flow += f ;
                limit -= f ;
                f1 += f ;
                if(dis[start] >= gnode) return f1 ;
                if(limit == 0) break ;
            }
            minh = min(minh , dis[v]) ;
        }
    }
    if(f1 == 0) {
        --gap[dis[u]] ;
        if(gap[dis[u]] == 0) dis[start] = gnode ;
        dis[u] = minh + 1 ;
        ++gap[dis[u]] ;
    }
    return f1 ;
}


int sap(int a , int b) {
    start = a , dest = b ;
    memset(gap , 0 , sizeof(gap)) ;
    memset(dis , 0 , sizeof(dis)) ;
    gap[start] = gnode ;
    int all = 0 ;
    while(dis[start] < gnode)  all += dfs(start , INF) ;
    return all ;
}

int main() {
    int t , tt = 0 ;
    scanf("%d" ,&t) ;
    while(t--) {
        printf("Case #%d: " , ++tt) ;
        scanf("%d%d" ,&n ,&m) ;
        init() ;
        sap(super_source , super_sink) ;
        add_edge(sink , source , INF) ;
        printf("%d\n" , sap(super_source , super_sink)) ;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章