HDU - 2732 (网络流)

http://acm.hdu.edu.cn/showproblem.php?pid=2732

题意:

在一个nxm的房间,有一些柱子,每个柱子都有个承受极限,有的柱子上又蜥蜴,问有多少蜥蜴跳不出去

思路:

一个超级源点S与蜥蜴相连,能跳出去的柱子与一个超级汇点相连,柱子之间相连,一个最大流模版题

#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <stdio.h>
#include <deque>

using namespace std;

#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 10005
#define eps 0.00000001
#define PI acos(-1.0)

struct Edge{
    int V, Weight, Next;
}edges[maxn << 2];


char Height[maxn][maxn];
char Maze[maxn][maxn];
int head[maxn << 1], Depth[maxn << 1], gap[maxn << 1], Cur[maxn << 1];
int tot, maxFlow, aug, isFind;
int S = 0, TT;
int N, D, MM, Cnt, Ans;

void init() {
    tot = 0;
    maxFlow = 0;
    memset(head, -1, sizeof(head));
    S = 0;
}

void AddEdge(int u, int v, int w) {
    edges[tot].V = v;
    edges[tot].Weight = w;
    edges[tot].Next = head[u];
    head[u] = tot ++;

    edges[tot].V = u;
    edges[tot].Weight = 0;
    edges[tot].Next = head[v];
    head[v] = tot ++;
}

bool Bfs(int Start, int End) {
    memset(Depth, -1, sizeof(Depth));
    std::queue<int> Que;
    Depth[Start] = 0;
    Que.push(Start);
    while (!Que.empty()) {
        int Vertex = Que.front();
        Que.pop();
        for (int i = head[Vertex]; i != -1; i = edges[i].Next) {
            if (Depth[edges[i].V] == -1 && edges[i].Weight > 0) {
                Depth[edges[i].V] = Depth[Vertex] + 1;
                Que.push(edges[i].V);
            }
        }
    }
    return Depth[End] != -1;
}

int Dfs(int Vertex, int End, int NowFlow) {
    if (Vertex == End || NowFlow == 0) {
        return NowFlow;
    }
    int UsableFlow = 0, FindFlow;
    for (int &i = Cur[Vertex]; i != -1; i = edges[i].Next) {
        if (edges[i].Weight > 0 && Depth[edges[i].V] == Depth[Vertex] + 1) {
            FindFlow = Dfs(edges[i].V, End, std::min(NowFlow - UsableFlow, edges[i].Weight));
            if (FindFlow > 0) {
                edges[i].Weight -= FindFlow;
                edges[i ^ 1].Weight += FindFlow;
                UsableFlow += FindFlow;
                if (UsableFlow == NowFlow) {
                    return NowFlow;
                }
            }
        }
    }
    if (!UsableFlow) {
        Depth[Vertex] = -2;
    }
    return UsableFlow;
}

int Dinic(int Start, int End) {
    int MaxFlow = 0;
    while (Bfs(Start, End)) {
        for (int i = 0; i <= N * MM * 2 + 1; ++i) {
            Cur[i] = head[i];
        }
        MaxFlow += Dfs(Start, End, INF);
    }
    return MaxFlow;
}




int main(int argc, const char * argv[]) {
    int T;
    scanf("%d", &T);
    for (int Case = 1; Case <= T; ++Case) {
        init();
        scanf("%d%d", &N, &D);
        for (int i = 1; i <= N; ++i) {
            scanf("%s", Height[i]);
            getchar();
        }
        MM = strlen(Height[1]);
        for (int i = 1; i <= N; ++i) {
            scanf("%s", Maze[i]);
            getchar();
        }
        Cnt = 0;
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= MM; ++j) {
                int Num = MM * (i - 1) + j;
                AddEdge(Num, N * MM + Num, (Height[i][j - 1] - '0'));
                if (Maze[i][j - 1] == 'L') {
                    AddEdge(0, Num, 1);
                    Cnt++;
                }
                bool flag = 0;
                for (int k = i - D; k <= i + D; ++k) {
                    for (int l = j - D; l <= j + D; ++l) {
                        if (k == i && l == j) {
                            continue;
                        }
                        if (k > 0 && k <= N && l > 0 && l <= MM) {
                            if (abs(k - i) + abs(l - j) <= D) {
                                AddEdge(N * MM + Num, MM * (k - 1) + l, INF);
                            }
                        }
                        else if (abs(k - i) + abs(l - j) <= D) {
                            if (!flag) {
                                AddEdge(N * MM + Num, N * MM * 2 + 1, INF);
                                flag = 1;
                            }
                        }
                    }
                }
            }
        }


        Ans = Cnt - Dinic(0, N * MM * 2 + 1);

        if (Ans == 0) {
            printf("Case #%d: no lizard was left behind.\n", Case);
        }
        else if (Ans == 1) {
            printf("Case #%d: %d lizard was left behind.\n", Case, Ans);
        }
        else {
            printf("Case #%d: %d lizards were left behind.\n", Case, Ans);
        }
    }
    return 0;
}

SAP

#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <stdio.h>
#include <deque>

using namespace std;

#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 10005
#define eps 0.00000001
#define PI acos(-1.0)

struct Edge{
    int v, w, nxt;
}edge[maxn << 2];

char Height[maxn][maxn];
char Maze[maxn][maxn];
int head[maxn << 1], gap[maxn << 1], dis[maxn << 1], cur[maxn << 1], aug[maxn << 1], pre[maxn << 1], tot, n, st, en;
int S, TT;
int N, D, MM, Cnt, Ans;


void init() {
    tot = 0;
    memset(head, -1, sizeof(head));

}

void addEdge(int u, int v, int w) {
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].nxt = head[u];
    head[u] = tot ++;

    edge[tot].v = u;
    edge[tot].w = 0;
    edge[tot].nxt = head[v];
    head[v] = tot ++;
}

int SAP(int n){
    int max_flow=0,u=S,v;
    int id,mindep;
    aug[S]=INF;
    pre[S]=-1;//st的父节点为-1
    memset(dis,0,sizeof(dis));
    memset(gap,0,sizeof(gap));
    gap[0]=n;//初始位置为0的有n个
    for(int i=0;i<=n;i++)
        cur[i]=head[i]; // 初始化当前弧为第一条弧
    while(dis[S]<n){ //当dis[st]< n时
        int flag=0;
        if(u==TT){
            max_flow+=aug[TT];
            for(v=pre[TT];v!=-1;v=pre[v]){     // 路径回溯更新残留网络
                id=cur[v];
                edge[id].w-=aug[TT];
                edge[id^1].w+=aug[TT];
                aug[v]-=aug[TT];   // 修改可增广量,以后会用到
                if(edge[id].w==0) // 不回退到源点,仅回退到容量为0的弧的弧尾
                    u=v;
            }
        }
        for(int i=cur[u];i!=-1;i=edge[i].nxt){
            v=edge[i].v;    // 从当前弧开始查找允许弧
            if(edge[i].w>0 && dis[u]==dis[v]+1){  // 找到允许弧
                flag=1;
                pre[v]=u;
                cur[u]=i;//记录u这个点的边的编号
                aug[v]=min(aug[u],edge[i].w);//更新aug[v]
                u=v;//u向下
                break;
            }
        }
        if(!flag){//没找到弧
            if(--gap[dis[u]]==0)    /* gap优化,层次树出现断层则结束算法 */
                break;
            mindep = n;
            cur[u]=head[u];
            for(int i=head[u];i!=-1;i=edge[i].nxt){
                v=edge[i].v;
                if(edge[i].w>0 && dis[v]<mindep){
                    mindep=dis[v];
                    cur[u]=i;   // 修改标号的同时修改当前弧
                }
            }
            dis[u]=mindep+1;
            gap[dis[u]]++;
            if(u!=S)  // 回溯继续寻找允许弧
                u=pre[u];
        }
    }
    return max_flow;
}


int main(int argc, const char * argv[]) {
    int T;
    scanf("%d", &T);
    for (int Case = 1; Case <= T; ++Case) {
        init();
        scanf("%d%d", &N, &D);
        for (int i = 1; i <= N; ++i) {
            scanf("%s", Height[i]);
            getchar();
        }
        MM = (int)strlen(Height[1]);
        TT = 2 * N * MM + 2;
        S = 2 * N * MM + 1;
        for (int i = 1; i <= N; ++i) {
            scanf("%s", Maze[i]);
            getchar();
        }
        Cnt = 0;
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= MM; ++j) {
                int Num = MM * (i - 1) + j;
                addEdge(Num, N * MM + Num, (Height[i][j - 1] - '0'));
                if (Maze[i][j - 1] == 'L') {
                    addEdge(S, Num, 1);
                    Cnt++;
                }
                bool flag = 0;
                for (int k = i - D; k <= i + D; ++k) {
                    for (int l = j - D; l <= j + D; ++l) {
                        if (k == i && l == j) {
                            continue;
                        }
                        if (k > 0 && k <= N && l > 0 && l <= MM) {
                            if (abs(k - i) + abs(l - j) <= D) {
                                addEdge(N * MM + Num, MM * (k - 1) + l, INF);
                            }
                        }
                        else if (abs(k - i) + abs(l - j) <= D) {
                            if (!flag) {
                                addEdge(N * MM + Num, TT, INF);
                                flag = 1;
                            }
                        }
                    }
                }
            }
        }


        Ans = Cnt - SAP(TT + 1);

        if (Ans == 0) {
            printf("Case #%d: no lizard was left behind.\n", Case);
        }
        else if (Ans == 1) {
            printf("Case #%d: %d lizard was left behind.\n", Case, Ans);
        }
        else {
            printf("Case #%d: %d lizards were left behind.\n", Case, Ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/81902875