您的位置:首页 > 其它

hdu 5352 MZL's City (最大流 || 费用流)

2015-08-05 14:18 357 查看

hdu 5352 MZL’s City

Description

MZL is an active girl who has her own country.

Her big country has N cities numbered from 1 to N.She has controled the country for so long and she only remebered that there was a big earthquake M years ago,which made all the roads between the cities destroyed and all the city became broken.She also remebered that exactly one of the following things happened every recent M years:

1.She rebuild some cities that are connected with X directly and indirectly.Notice that if a city was rebuilt that it will never be broken again.

2.There is a bidirectional road between city X and city Y built.

3.There is a earthquake happened and some roads were destroyed.

She forgot the exactly cities that were rebuilt,but she only knew that no more than K cities were rebuilt in one year.Now she only want to know the maximal number of cities that could be rebuilt.At the same time she want you to tell her the smallest lexicographically plan under the best answer.Notice that 8 2 1 is smaller than 10 0 1.

Input

The first contains one integer T(T<=50),indicating the number of tests.

For each test,the first line contains three integers N,M,K(N<=200,M<=500,K<=200),indicating the number of MZL’s country ,the years happened a big earthquake and the limit of the rebuild.Next M lines,each line contains a operation,and the format is “1 x” , “2 x y”,or a operation of type 3.

If it’s type 3,first it is a interger p,indicating the number of the destoyed roads,next 2*p numbers,describing the p destoyed roads as (x,y).It’s guaranteed in any time there is no more than 1 road between every two cities and the road destoyed must exist in that time.

Output

The First line Ans is the maximal number of the city rebuilt,the second line is a array of length of tot describing the plan you give(tot is the number of the operation of type 1).

Sample Input

1

5 6 2

2 1 2

2 1 3

1 1

1 2

3 1 1 2

1 2

Sample Output

3

0 2 1

题目大意:有n座城市。m年前发生了一场地震,破坏了所有城市,和城市间的所有道路。在过去的m年每一年都会进行一个操作:操作1,格式(1 a),修复与城市a直接相连或间接相连或该城市本身的城市,修复的城市数量不能超过k座,被修复的城市,不会再被地震破坏。操作2,格式(2 a b),在城市a,b之间建一条双向边,不会有重边。操作3,格式(3 p p个(a, b)),又发生了一次地震,摧毁了p条道路,后面是p组数据。问最多能修复多少城市,并每次进行操作1修复的城市必须是最小字典序,输出该最小字典序的修复方案。

解题思路:最大流:动态建图做最大流。设置超级源点连向所有操作1后面的点,容量为k。设置超级汇点,使所有城市连向超级汇点,容量为1。然后从最后一个一操作开始,把可以跟该城市直接或间接相连的城市,连起来,容量为1,求一次最大流。就这样从后往前求出每次最大流,相加,就是最后可以修复的最多的城市。并记录下每次求出来的最大流,逆序输出就是字典序最小的修复方案。

费用流:设置超级源点,连向每一个1操作后的城市,容量为k,费用为0。然后设置一个超级汇点,使每一个城市,连向超级汇点,容量为1,费用为0。然后开始匹配1操作后的城市以及它所直接相连或间接相连的城市,费用从开始到最后递减,这样就会先修复后面的城市,保证字典序最小。

最大流

[code]#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;

const int N = 1005;
const int M = 100505;
const int INF = 0x3f3f3f3f;
typedef long long ll;

int n, m, k, cnt, s, t;

int G

, mark

;
int first_M
, Next_M[M], v_M[M], e;

int ec, head
, first
, que
, lev
;
int Next[M], to[M], f[M];

int rec
;

void addEdge(int a,int b,int c) {
    to[ec] = b;
    f[ec] = c;
    Next[ec] = first[a];
    first[a] = ec++;

    to[ec] = a;
    f[ec] = 0;
    Next[ec] = first;
    first[b] = ec++;
}

int BFS() {
    int kid, now, hd = 0, tl = 1, i;
    memset(lev, 0, sizeof(lev));
    que[0] = s, lev[s] = 1;
    while (hd < tl) {
        now = que[hd++];
        for (i = first[now]; i != -1; i = Next[i]) {
            kid = to[i];    
            if (!lev[kid] && f[i]) {
                lev[kid] = lev[now] + 1;    
                if (kid == t) return 1;
                que[tl++] = kid;
            }
        }
    }
    return 0;
}

int DFS(int now, int sum) {
    int kid, flow, rt = 0;
    if (now == t) return sum;
    for (int i = head[now]; i != -1 && rt < sum; i = Next[i]) {
        head[now] = i;  
        kid = to[i];
        if (lev[kid] == lev[now] + 1 && f[i]) {
            flow = DFS(kid, min(sum - rt, f[i]));
            if (flow) {
                f[i] -= flow;
                f[i^1] += flow;
                rt += flow;
            } else lev[kid] = -1;   
        }           
    }
    return rt;
}

int dinic() {
    int ans = 0;
    while (BFS()) {
        for (int i = 0; i <= t; i++) {
            head[i] = first[i];
        }           
        ans += DFS(s, INF);
    }
    return ans;
}   

void init() {
    ec = 0;
    memset(first, -1, sizeof(first));
    for (int i = 0; i <= N; i++) rec[i] = k;
    cnt = 0, e = 0;
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= n; j++) {
            G[i][j] = 0;    
        }   
    }
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            mark[i][j] = 0;
        }   
    }
    memset(first_M, -1, sizeof(first_M));
}

void add(int u, int v) {
    v_M[e] = v;
    Next_M[e] = first_M[u];
    first_M[u] = e++;
}

void DFS_M(int x, int u) {
    add(x, u);
    mark[x][u] = 1;
    for (int i = 1; i <= n; i++) {
        if (!G[u][i] || mark[x][i]) continue;   
        DFS_M(x, i);
    } 
}

int solve() {
    s = 0, t = n + cnt + 1;
    int ans = 0;
    for (int i = 1; i <= cnt; i++) addEdge(s, i, k);     
    for (int i = 1; i <= n; i++) addEdge(i + cnt, t, 1);
    for (int i = cnt; i >= 1; i--) {
        printf("%d : ", i);
        for (int j = first_M[i]; j != -1; j = Next_M[j]) {
            printf("%d ", v_M[j]);
            addEdge(i, v_M[j] + cnt, 1);    
        }puts("");
        int temp = dinic();
        ans += temp;
        rec[i] = temp;
    }
    return ans;
}

void input() {
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 0; i < m; i++) {
        int type, a, b;
        scanf("%d", &type); 
        if (type == 1) {
            scanf("%d", &a);
            cnt++;          
            DFS_M(cnt, a);
        } else if (type == 2) {
            scanf("%d %d", &a, &b);
            G[a][b] = G[b][a] = 1;
        } else if (type == 3) {
            int p;
            scanf("%d", &p);    
            while (p--) {
                scanf("%d %d", &a, &b); 
                G[a][b] = G[b][a] = 0;
            }
        }
    }
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        init();
        input();    
        printf("%d\n", solve());
        for (int i = 1; i <= cnt; i++) {
            if (i != 1) printf(" ");
            printf("%d", rec[i]);   
        }
        printf("\n");
    }
    return 0;
}


[b]费用流


[code]#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
using namespace std;

const int N = 1505;
const int M = 100505;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int n, m, k, cnt, s, t;
int pre
, inq
; 
ll a
, d
;
int first_M
, Next_M[M], v_M[M], e, mark

;
int Gra

;

struct Edge{
    int from, to;
    ll cap, flow;
    ll cos;
};

vector<Edge> edges;
vector<int> G[M];

void addEdge(int from, int to, ll cap, ll flow, ll cos) {
    edges.push_back((Edge){from, to, cap, 0, cos});
    edges.push_back((Edge){to, from, 0, 0, -cos});
    int m = edges.size();
    G[from].push_back(m - 2); 
    G[to].push_back(m - 1);
}

int BF(int s, int t, ll& flow, ll& cost) {
    queue<int> Q;
    memset(inq, 0, sizeof(inq));
    memset(a, 0, sizeof(a));
    memset(pre, 0, sizeof(pre));
    for (int i = 0; i < N; i++) d[i] = INF;
    d[s] = 0;
    a[s] = INF;
    inq[s] = 1;
    int flag = 1;
    pre[s] = 0;
    Q.push(s);
    while (!Q.empty()) {
        int u = Q.front(); Q.pop();
        inq[u] = 0;
        for (int i = 0; i < G[u].size(); i++) {
            Edge &e = edges[G[u][i]];
            if (e.cap > e.flow && d[e.to] > d[u] + e.cos) {
                d[e.to] = d[u] + e.cos;
                a[e.to] = min(a[u], e.cap - e.flow);
                pre[e.to] = G[u][i];
                if (!inq[e.to]) {
                    inq[e.to] = 1;
                    Q.push(e.to);
                }
            }   
        }
        flag = 0;
    }
    if (d[t] == INF) return 0;
    flow += a[t];
    cost += (ll)d[t] * (ll)a[t];
    for (int u = t; u != s; u = edges[pre[u]].from) {
        edges[pre[u]].flow += a[t];
        edges[pre[u]^1].flow -= a[t];
    }
    return 1;
}

int MCMF(int s, int t, ll& cost) {
    ll flow = 0;
    cost = 0;       
    while (BF(s, t, flow, cost));
    return flow;
}

void init() {
    cnt = 0;
    e = 0;
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= n; j++) {
            Gra[i][j] = 0;  
        }
    }
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            mark[i][j] = 0;
        }   
    }
    memset(first_M, -1, sizeof(first_M));
    for (int i = 0; i < M; i++) G[i].clear();
    edges.clear();
}

void add(int u, int v) {
    v_M[e] = v;
    Next_M[e] = first_M[u];
    first_M[u] = e++;
}

void DFS(int x, int u) {
    add(x, u);
    mark[x][u] = 1;
    for (int i = 1; i <= n; i++) {
        if (!Gra[u][i] || mark[x][i]) continue; 
        DFS(x, i);
    } 
}

void input() {
    int type, a, b;
    for (int i = 0; i < m; i++) {
        scanf("%d", &type); 
        switch(type) {
            case 1:
                scanf("%d", &a);    
                cnt++;
                DFS(cnt, a);
                break;
            case 2:
                scanf("%d %d", &a, &b);
                Gra[a][b] = Gra[b][a] = 1;
                break;
            case 3:
                int p;
                scanf("%d", &p);
                while (p--) {
                    scanf("%d %d", &a, &b); 
                    Gra[a][b] = Gra[b][a] = 0;
                }
                break;
        }
    }
}

int solve() {
    s = 0, t = n + cnt + 1;
    for (int i = 1; i <= cnt; i++) addEdge(s, i, k, 0, 0);
    for (int i = 1; i <= n; i++) addEdge(i + cnt, t, 1, 0, 0);
    for (int i = cnt; i >= 1; i--) {
        for (int j = first_M[i]; j != -1; j = Next_M[j]) {
            addEdge(i, v_M[j] + cnt, 1, 0, cnt - i);    
        }
    }
    ll cost;
    return MCMF(s, t, cost);
}
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d %d", &n, &m, &k);
        init();
        input();
        printf("%d\n", solve());
        for (int i = 0; i < G[0].size(); i++) {
            if (i != 0) printf(" ");
            printf("%lld", edges[G[0][i]].flow);    
        }puts("");
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: