网络流/Dinic(POJ - 1087 A Plug for UNIX )

网络流算法详解与实践

题目链接
一道比较基础的网络流。

超源点->插座->电器->超汇点

一开始是想得是统计每个插座的数量,以这个数量作为超源点对插座的权值,不过后来发现,只有每次都建议个权值为1的边就可以了。另外,因为转换器的供应是无限的,所以边权应该是inf。其余边权值是1。后跑一边Dinic。
下面是ac代码:

#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <string>
#include <cstdio>
#include <cstdlib>
#define ll long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
map<string, int> mp;
int he[N], ver[N], ne[N];
int e[N], l[N];
int n, m, k;
int _cnt;
int tot;
void init()
{
    memset(he, 0, sizeof(he));
    mp.clear();
    tot = 1;
    _cnt = 2;
}
void add(int x, int y, int w)
{
    ver[++tot] = y;
    ne[tot] = he[x];
    e[tot] = w;
    he[x] = tot;
    ver[++tot] = x;
    ne[tot] = he[y];
    e[tot] = 0;
    he[y] = tot;
}
bool bfs(int s, int en)
{
    memset(l, 0, sizeof(l));
    queue<int> q;
    q.push(s);
    l[s] = 1;
    while(q.size())
    {
        int u = q.front();
        q.pop();
        if (u == en) return 1;
        for (int i = he[u]; i; i = ne[i])
        {
            int y = ver[i];
            if (!l[y] && e[i])
            {
                l[y] = l[u] + 1;
                q.push(y);
            }
        }
    }
    return 0;
}
int dfs(int u, int MaxFlow, int en)
{
    if (u == en) return MaxFlow;
    int uflow = 0;
    for (int i = he[u]; i; i = ne[i])
    {
        int y = ver[i];
        if (l[y] == l[u]+1 && e[i])
        {
            int flow = min(e[i], MaxFlow - uflow);
            flow = dfs(y, flow, en);
            e[i] -= flow;
            e[i^1] += flow;
            uflow += flow;
            if (uflow == MaxFlow)
                break;
        }
    }
    if (uflow == 0)
        l[u] = 0;
    return uflow;
}
int Dinic()
{
    int MaxFlow = 0;
    while(bfs(0, 1))
        MaxFlow += dfs(0, inf, 1);
    return MaxFlow;
}
int main()
{
    while(scanf("%d", &n) != EOF)
    {
        init();
        for (int i = 0; i < n; i++)
        {
            string te;
            cin >> te;
            if (mp.find(te) == mp.end()) mp[te] = _cnt++;
            add(0, mp[te], 1);
        }
        scanf("%d", &m);
        for (int i = 0; i < m; i++)
        {
            string ta, tb;
            cin >> ta >> tb;
            if (mp.find(ta) == mp.end()) mp[ta] = _cnt++;
            if (mp.find(tb) == mp.end()) mp[tb] = _cnt++;
    //        cout << mp[tb] <<" " << mp[ta] <<" " << 1 <<endl;
            add(mp[tb], mp[ta], 1);
    //        cout << mp[ta] <<" " << 1 <<" " << 1 <<endl;
            add(mp[ta], 1, 1);
        }
        scanf("%d", &k);
        for (int i = 0; i < k; i++)
        {
            string ta, tb;
            cin >> ta >> tb;
            if (mp.find(ta) == mp.end()) mp[ta] = _cnt++;
            if (mp.find(tb) == mp.end()) mp[tb] = _cnt++;
    //        cout << mp[tb] <<" " << mp[ta] <<" " << inf <<endl;
            add(mp[tb], mp[ta], inf);
        }
     //   for (it=mp.begin(); it != mp.end(); it++)
       // {
     //       cout << it->first <<" " << it->second <<endl;
   //     }
        int ans = Dinic();
        printf("%d\n", m - ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值