HDU 4067 Random Maze 費用流

Random Maze

Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1114    Accepted Submission(s): 387


php

Problem Description
In the game 「A Chinese Ghost Story」, there are many random mazes which have some characteristic:
1.There is only one entrance and one exit.
2.All the road in the maze are unidirectional.
3.For the entrance, its out-degree = its in-degree + 1.
4.For the exit, its in-degree = its out-degree + 1.
5.For other node except entrance and exit, its out-degree = its in-degree.

There is an directed graph, your task is removing some edge so that it becomes a random maze. For every edge in the graph, there are two values a and b, if you remove the edge, you should cost b, otherwise cost a.
Now, give you the information of the graph, your task if tell me the minimum cost should pay to make it becomes a random maze.

 

 

Input
The first line of the input file is a single integer T.
The rest of the test file contains T blocks.
For each test case, there is a line with four integers, n, m, s and t, means that there are n nodes and m edges, s is the entrance's index, and t is the exit's index. Then m lines follow, each line consists of four integers, u, v, a and b, means that there is an edge from u to v.
2<=n<=100, 1<=m<=2000, 1<=s, t<=n, s != t. 1<=u, v<=n. 1<=a, b<=100000
 

 

Output
For each case, if it is impossible to work out the random maze, just output the word 「impossible」, otherwise output the minimum cost.(as shown in the sample output)
 

 

Sample Input
2 2 1 1 2 2 1 2 3 5 6 1 4 1 2 3 1 2 5 4 5 5 3 2 3 3 2 6 7 2 4 7 6 3 4 10 5
 

 

Sample Output
Case 1: impossible Case 2: 27
 

 

Source
 
題目大意:
一個可行圖須要知足如下條件:
1.全部的路都是單向的;
2.對於入口 : 出度 = 入度 + 1;
3.對於出口 : 入度 = 出口 + 1;
4.對於其餘點 : 入度 = 出度;
給你一個有向圖,n個點,m條邊,起點S,終點T,每條邊存在圖中要花費a元,從圖中刪除要花費b元。問最少須要花費多少使得圖成爲一個可行圖。
 
題目分析:
易知,若是是一個可行圖,則添加T到S的邊剛好是一個歐拉回路(全部點的出度 = 入度)。
怎樣建圖好呢?咱們能夠先貪心建圖,將花費最小的狀況構建出來,無論是否可行!
*對於每條邊(u,v),若是a  >  b,則建邊(v,u,1,a - b),sum += b,默認這條邊是不存在於圖中的,因爲不存在圖中因此點的出度及入度不變化。
*對於每條邊(u,v),若是a <= b,則建邊(u,v,1,b - a),sum += a,默認這條邊是存在於圖中的,且++deg[u], --deg[v],這裏deg[u] = out[u] - in[u]。
*對於S,T,鏈接(T,S),即++deg[T], --deg[S](就是爲了使得圖中每一個點的情況可以相同)。
至此,最小狀況構建完畢,接下來咱們該怎麼才能使得整幅圖符合條件?
首先,添加超級源s,超級匯t。
由構圖方法能夠知道,對於每一個點u,若是deg[u] > 0,說明從它出發的邊大於指向它的邊,建邊(s,u,deg[u],0),輸出流量,選擇恢復指向它的邊或者刪除從它出發的邊,流量用完則該點的出度 = 入度。對於每一個點v,若是deg[v] < 0,說明從它出發的邊少於指向它的邊,建邊(v,t,deg[v],0),接收流量,選擇恢復從它出發的邊或者刪除指向它的邊,所有接收則該點的出度 = 入度。
對於圖中的每一個點,流向它的邊有兩種狀況,從它出發的邊也有兩種狀況。當流向它的是原圖的正向邊時(即在原圖中b >= a),流過它的時候,至關於刪除這條邊。接下來從這個點出發,當流出的邊是原圖的正向邊時(即在原圖中b >= a),至關於刪除這條邊,剛好與流進的邊抵消,度保持不變;當流出的邊是原圖的反向邊(即在原圖中b < a),至關於恢復了指向它的反向邊,一樣抵消了入邊的影響。對於指向該點的是原圖的反向邊時(即在原圖中b < a)同理。對於出度大於入度的點,接收源點流出的流量至關於給它機會抵消多餘的出度;對於入度大於出度的點,流量流入匯點至關於給它機會抵消多餘的入度;對於中間點,由上述可知不管怎麼流都不會影響他們的出入度平衡。
最後,只要跑一次最小費用最大流,若是滿流(即流量等於多餘的入度或者多餘的出度),則有解,解爲一開始存在於圖中的費用sum+流量flow;不然無解。另外可知,若是有解,則全部流過的邊都是須要恢復或者刪除的邊。
若是會用一些畫圖軟件的話或許能描述的更清楚一些QUQ。。。
 
代碼以下:
 
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define REP(i, n) for(int i = 1; i <= n; ++i)
#define MS0(X) memset(X,  0, sizeof X)
#define MS1(X) memset(X, -1, sizeof X)
using namespace std;
const int maxE = 3000000;
const int maxN = 105;
const int oo = 0x3f3f3f3f;
struct Edge{
    int v, c, w, n;
};
Edge edge[maxE];
int adj[maxN], l;
int d[maxN], cur[maxN], a[maxN];
int inq[maxN], Q[maxE], head, tail;
int cost, flow, s, t;
int n, m, S, T;
int deg[maxN];
void addedge(int u, int v, int c, int w){
    edge[l].v = v; edge[l].c = c; edge[l].w =  w; edge[l].n = adj[u]; adj[u] = l++;
    edge[l].v = u; edge[l].c = 0; edge[l].w = -w; edge[l].n = adj[v]; adj[v] = l++;
}
int SPFA(){
    memset(d, oo, sizeof d);
    memset(inq, 0, sizeof inq);
    head = tail = 0;
    d[s] = 0;
    a[s] = oo;
    cur[s] = -1;
    Q[tail++] = s;
    while(head != tail){
        int u =  Q[head++];
        inq[u] = 0;
        for(int i = adj[u]; ~i; i = edge[i].n){
            int v = edge[i].v;
            if(edge[i].c && d[v] > d[u] + edge[i].w){
                d[v] = d[u] + edge[i].w;
                cur[v] = i;
                a[v] = min(edge[i].c, a[u]);
                if(!inq[v]){
                    inq[v] = 1;
                    Q[tail++] = v;
                }
            }
        }
    }
    if(d[t] == oo) return 0;
    flow += a[t];
    cost += a[t] * d[t];
    for(int i = cur[t]; ~i; i = cur[edge[i ^ 1].v]){
        edge[i].c -= a[t];
        edge[i ^ 1].c += a[t];
    }
    return 1;
}
int MCMF(){
    flow = cost = 0;
    while(SPFA());
    return flow;
}
void work(){
    int u, v, a, b, sum = 0;
    scanf("%d%d%d%d", &n, &m, &S, &T);
    MS1(adj);
    MS0(deg);
    l = 0;
    while(m--){
        scanf("%d%d%d%d", &u, &v, &a, &b);
        if(a > b){
            addedge(v, u, 1, a - b);
            sum += b;
        }
        else{
            addedge(u, v, 1, b - a);
            sum += a;
            ++deg[u];
            --deg[v];
        }
    }
    ++deg[T];
    --deg[S];
    s = 0; t = n + 1;
    int nflow = 0;
    REP(i, n){
        if(deg[i] > 0){
            addedge(s, i, deg[i], 0);
            nflow += deg[i];
        }
        if(deg[i] < 0){
            addedge(i, t, -deg[i], 0);
        }
    }
    MCMF();
    if(nflow == flow){
        printf("%d\n", cost + sum);
    }
    else printf("impossible\n");
}
int main(){
    int T, cas;
    for(scanf("%d", &T), cas = 1; cas <= T; cas++){
        printf("Case %d: ", cas);
        work();
    }
    return 0;
}
HDU 4067
相關文章
相關標籤/搜索