HDU 1532 Drainage Ditches (EK算法求最大流模板题)

原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=1532

关于利用vector建图的一些理解

  e[u].push_back((edge){v,w,e[v].size()});
  e[v].push_back((edge){u,0,e[u].size()-1});
 /*
 先声明struct  edge{
int to,cap,rev;//分别表示终点,容量,反向边
}
就比如说是第1条,说明从v连向u的边是G[v]中的第e[v].size()条
*/

下面是利用前向星建的图

#include <cmath>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 5;
struct edge {//前向星
    int v, nxt, w;
}edge[maxn];

struct node {
    int v, id;
}pre[maxn];

int n, m, cnt;

int head[maxn];
void init() {
    cnt = 0;
    memset(edge, 0, sizeof(edge));
    memset(head, -1, sizeof(head));
}

void add_edge(int u, int v, int w) {
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].nxt = head[u];
    head[u] = cnt++;
}

bool vis[maxn];
bool bfs(int s, int t) {//bfs寻找增广路
    queue<int>q;
    memset(vis, 0, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    pre[s].v = s;
    vis[s] = true;
    q.push(s);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = edge[i].nxt) {
            int v = edge[i].v;
            if(!vis[v] && edge[i].w) {
                pre[v].v = u;//v的前驱节点是u,第2个v是前驱节点的意思
                pre[v].id = i;//v的前驱节点的线段编号是i
                //这条边是连接u和v的边
                vis[v] = true;
                if(v == t) return true;
                q.push(v);
            }
        }
    }
    return false;
}

int EK(int s, int t) {
    int ans = 0;
    while(bfs(s, t)) {
        int mi = INF;
        for(int i = t; i != s; i = pre[i].v) {
            mi = min(mi, edge[pre[i].id].w);//每次寻找在bfs过程中当前可以使用的最少的流量
        }
        for(int i = t; i != s; i = pre[i].v) {
            //pre数组其实就是i记录了当前bfs寻找增广路的路径,从终点开始倒着寻找
            edge[pre[i].id].w -= mi;//正向边--
            edge[pre[i].id ^ 1].w += mi;//反向边++
            //因为建边的时候是相邻的,所以可以利用^1得到反向边的id
        }
        ans += mi;
    }
    return ans;
}
int main() {
    while(~scanf("%d%d", &m, &n)) {
        init();
        for(int i = 1; i <= m; i++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add_edge(u, v, w);//正向建边
            add_edge(v, u, 0);//反向建权值为0的边
        }
        int ans = EK(1, n);
        printf("%d\n", ans);
    }
    return 0;
}

下面是vector建图的,网上找的,还没转化为自己的板子

#include<stdio.h>
#include<string.h>
#include<vector>
#define maxn 222
#define inf 0x3f3f3f3f
using namespace std;
struct edge{
    int to;
    int cap;
    int rev;
};
vector<edge>e[maxn];
int book[maxn];
int dfs(int cur,int end,int flow){
    if(cur == end)
        return flow;
    book[cur] = 1;
    for(int i = 0;i<e[cur].size();i++){
        edge &temp = e[cur][i];
        if(!book[temp.to] && temp.cap>0){
            int d = dfs(temp.to,end,min(flow,temp.cap));
            if(d > 0){
                temp.cap -= d;
                e[temp.to][temp.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i = 1;i<=n;i++)
            e[i].clear();
        int u,v,w;
        for(int i = 0;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            e[u].push_back((edge){v,w,e[v].size()});
            e[v].push_back((edge){u,0,e[u].size()-1});
        }    
        int ans = 0;
        while(1){
            memset(book,0,sizeof(book));
            int temp = dfs(1,m,inf);
            if(temp == 0)
                break;
            ans += temp;
        }
        printf("%d\n",ans);
    }
    return 0;
}

邻接矩阵版本

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 300;
const int MAX_INT = ((1 << 31) - 1);

int n;                                      // 图中点的数目
int pre[MAXN];                              // 从 s - t 中的一个可行流中, 节点 i 的前序节点为 Pre[i];
bool vis[MAXN];                             // 标记一个点是否被访问过
int mp[MAXN][MAXN];                         // 记录图信息

bool bfs(int s, int t){
    queue <int> que;
    memset(vis, 0, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    pre[s] = s;
    vis[s] = true;
    que.push(s);
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(int i = 1; i <= n; i++){
            if(mp[u][i] && !vis[i]){
                pre[i] = u;
                vis[i] = true;
                if(i == t) return true;
                que.push(i);
            }
        }
    }
    return false;
}

int EK(int s, int t){
    int ans = 0;
    while(bfs(s, t)){
        int mi = MAX_INT;
        for(int i = t; i != s; i = pre[i]){
            mi = min(mi, mp[pre[i]][i]);
        }
        for(int i = t; i != s; i = pre[i]){
            mp[pre[i]][i] -= mi;
            mp[i][pre[i]] += mi;
        }
        ans += mi;
    }
    return ans;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81294322