1. 程式人生 > >【洛谷P1343】地震逃生 解題報告

【洛谷P1343】地震逃生 解題報告

P1343 地震逃生

題目描述

汶川地震發生時,四川XX中學正在上課,一看地震發生,老師們立刻帶領x名學生逃跑,整個學校可以抽象地看成一個有向圖,圖中有n個點,m條邊。1號點為教室,n號點為安全地帶,每條邊都只能容納一定量的學生,超過樓就要倒塌,由於人數太多,校長決定讓同學們分成幾批逃生,只有第一批學生全部逃生完畢後,第二批學生才能從1號點出發逃生,現在請你幫校長算算,每批最多能運出多少個學生,x名學生分幾批才能運完。

輸入輸出格式

輸入格式:

第一行3個整數n,m,x(\(x<2^{31},n \le 200,m \le 2000\));以下m行,每行三個整數a,b,c(a1,a<>b,0描述一條邊,分別代表從a點到b點有一條邊,且可容納c名學生。

輸出格式:

兩個整數,分別表示每批最多能運出多少個學生,x名學生分幾批才能運完。如果無法到達目的地(n號點)則輸出“Orz Ni Jinan Saint Cow!”

輸入輸出樣例

輸入樣例#1:

6 7 7
1 2 1
1 4 2
2 3 1
4 5 1
4 3 1
3 6 2
5 6 1

輸出樣例#1:

3 3

說明

【註釋】

比如有圖

1 2 100

2 3 1

100個學生先衝到2號點,然後1個1個慢慢沿2-3邊走過去

18神牛規定這樣是不可以的……

也就是說,每批學生必須同時從起點出發,並且同時到達終點


演算法

網路最大流。 請大家先掌握,這裡不詳細講。

思路

很明顯,1是源點,n是匯點,直接網路最大流模板即可。
這裡資料十分小,用Edmonds-Karp或Dinic都可以。
我才不告訴你EK怎麼打忘光了
用網路流求出了每次能通過的學生數ans後,就可以直接求出分成\(floor(frac{ans - 1}x) + 1\)次通過。總體來說不是很難,具體看程式碼QAQ

程式碼

#include<bits/stdc++.h>
using namespace std;
#define open(s) freopen( s".in", "r", stdin ), freopen( s".out", "w", stdout )
#define MAXN 205
#define MAXM 4005
//建雙向邊要開兩倍別忘了

int n, m, X, ans;//小寫的x會衝突(下5行) QAQ 只好改大寫
int hd[MAXN], nxt[MAXM], to[MAXM], val[MAXM], tot(1);//MAXN、MAXM別看錯了 ~~我才不告訴你為了這個我錯了好幾遍~~
//還有tot要賦值為1**千萬**別忘了 ~~我又為這個除錯了好久~~(不用成對儲存的請忽略這句話)
int dis[MAXN];
queue<int> Q;
int S, T;
int x, y;

void Add( int x, int y, int z ){nxt[++tot] = hd[x]; hd[x] = tot; to[tot] = y; val[tot] = z;}//鏈式前向星萬歲!~~雖然鄰接矩陣也可以~~

bool BFS(){//分層
    while( !Q.empty() ) Q.pop();//清空queue 懶得手打佇列QAQ
    memset( dis, 0, sizeof dis );//初始化別忘了
    Q.push(S); dis[S] = 1;
    while( !Q.empty() ){
        x = Q.front(); Q.pop();
        for ( int i = hd[x]; i; i = nxt[i] ){
            if ( val[i] && !dis[to[i]] ){
                dis[to[i]] = dis[x] + 1;
                Q.push( to[i] );
                if ( to[i] == T ) return 1;
            }
        }
    }
    return 0;
}

int DFS( int x, int fl ){
    if ( x == T ) return fl;
    int res(fl), k;
    for ( int i = hd[x]; i && res; i = nxt[i] ){
        if ( ( dis[to[i]] == dis[x] + 1 ) && val[i] ){
            k = DFS( to[i], min( res, val[i] ) );
            if ( !k ) dis[to[i]] = 0; //剪枝! 不能再增廣的點去掉!
            val[i] -= k; val[i^1] += k; res -= k; //成對儲存
        }
    }
    return fl - res;
}

int main(){
    scanf( "%d%d%d", &n, &m, &X );
    S = 1; T = n;
    for ( int i = 1; i <= m; ++i ){
        int x, y, z; scanf( "%d%d%d", &x, &y, &z );
        Add( x, y, z ); Add( y, x, 0 );
    }
    
    int t;
    while( BFS() ) while( ( t = DFS( S, INT_MAX ) ) > 0 ) ans += t;
    
    if ( ans ) printf( "%d %d\n", ans, ( X - 1 ) / ans + 1 );//同上
    else printf( "Orz Ni Jinan Saint Cow!\n" ); //這是誰?
    return 0;
}