网络流

参考博客:
网络流–最大流(ek算法详解)
探网络流:dinic/EK算法学习笔记

最大流:

题目:Drainage Ditches

纯模板题
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int level[maxn];
queue<int>q;
int S, T, n, m;
void add(int x, int y, int z){
     cost[cnt] = z;
     to[cnt] = y;
     nex[cnt] = h[x];
     h[x]= cnt++;
}

bool bfs(){
    queue<int>q;
    memset(level,-1,sizeof(level));
    level[S] = 0;
    q.push(S);
    while(!q.empty()){
        int tp = q.front();
        q.pop();
        for(int i = h[tp]; i != -1; i = nex[i]){
            int t = to[i];
            if(level[t] == -1 && cost[i]){
                level[t] = level[tp] + 1;
                q.push(t);
                if(t == T)return 1;
            }
        }
    }
    return 0;
}
int dfs(int u, int flow){
    if(u == T)return flow;
    int ret = flow, k;
    for(int i = h[u]; i != -1  && ret; i = nex[i]){
        int v = to[i];
        if(cost[i] != 0&& level[u]+1 == level[v]){
            k = dfs(v, min(cost[i], ret));
            if(!k)level[v] = -1;
            ret -= k;
            cost[i] -= k;
            cost[i^1] += k;
            //if(flow == 0)break;
        }

    }
    return flow - ret;
}
int dinic(){
    int ans = 0, flow;
    while(bfs())
        while(flow = dfs(S, INF))
            ans += flow;
    return ans;
}


int main(){
    while(~scanf("%d %d", &n, &m)){
    memset(h, -1, sizeof h);
    S = 1;
    T = m;
    for(int i = 1; i <= n; i++){
        int x, y, z;
        scanf("%d %d %d", &x, &y, &z);
        add(x, y, z);
        add(y, x, 0);
    }
    printf("%d\n",dinic());
}
return 0;
}


题目:Escape

思路:本题的思路一看就非常简单就是在就是建一个网络流的图,所以我就这么写了,但是它T了,所有这么做思路是没有毛病的但是会超时的。有一个前提要求m<=10,所以可以考虑状态压缩,最多有1024种,所以可以考虑状态压缩。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
const int INF = 2147483647;
int cnt = 0, cost[maxn], h[maxn], to[maxn], nex[maxn];
int level[maxn];
map<int, int> record;
queue<int>q;
int S, T, n, m;
void add(int x, int y, int z)
{
    cost[cnt] = z;
    to[cnt] = y;
    nex[cnt] = h[x];
    h[x]= cnt++;

    cost[cnt] = 0;
    to[cnt] = x;
    nex[cnt] = h[y];
    h[y] = cnt++;
}
inline int read()
{
    char ch = getchar();
    int x = 0, f = 1;
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while('0' <= ch && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

bool bfs()
{
    queue<int>q;
    memset(level,-1,sizeof(level));
    level[S] = 0;
    q.push(S);
    while(!q.empty())
    {
        int tp = q.front();
        q.pop();
        for(int i = h[tp]; i != -1; i = nex[i])
        {
            int t = to[i];
            if(level[t] == -1 && cost[i])
            {
                level[t] = level[tp] + 1;
                q.push(t);
                if(t == T)
                    return 1;
            }
        }
    }
    return 0;
}
int dfs(int u, int flow)
{
    if(u == T)return flow;
    int ret = flow, k;
    for(int i = h[u]; i != -1  && ret; i = nex[i])
    {
        int v = to[i];
        if(cost[i] != 0&& level[u]+1 == level[v])
        {
            k = dfs(v, min(cost[i], ret));
            if(!k)level[v] = -1;
            ret -= k;
            cost[i] -= k;
            cost[i^1] += k;
            //if(flow == 0)break;
        }

    }
    return flow - ret;
}
int dinic()
{
    int ans = 0, flow;
    while(bfs())
    {
        while(flow = dfs(S, INF))
            ans += flow;
    }
    return ans;
}

int main()
{
    int v;
    while(~scanf("%d %d", &n, &m))
    {
        memset(h, -1, sizeof h);
        S = 0;
        cnt = 0;
        int ret = 0;
        record.clear();
        for(int i = 1; i <= n; i++)
        {
            ret = 0;
            for(int j = 1; j <= m; j++)
            {
                v = read();
                if(v)ret += (v<<j);//状态压缩
            }
            record[ret]++;//同一种状态的人放在一块
        }
        int tot = 0, len = record.size();
        for(auto &it:record)
        {
            tot++;
            for(int i = 1; i <= m; i++)
            {
                if(it.first&(1<<i))
                {
                    add(tot, len+i, it.second);
                }
            }
            add(S, tot, it.second);
        }
        T = tot+m+1;
        for(int i = 1; i <= m; i++)
        {
            v = read();
            add(i+tot, T, v);
        }
        if(dinic() == n)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

题目:Task Schedule

思路:本题的思路就建一张网络图,源点为0,汇点为1+max+n,0到1~n的全职为pi,然后再分别建立i到si ~ ei的路径。
参考博客:hdu3572 最大流
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int level[maxn];
queue<int>q;
int S, T, n, m;
void add(int x, int y, int z){
     cost[cnt] = z;
     to[cnt] = y;
     nex[cnt] = h[x];
     h[x]= cnt++;
}

bool bfs(){
    queue<int>q;
    memset(level,-1,sizeof(level));
    level[S] = 0;
    q.push(S);
    while(!q.empty()){
        int tp = q.front();
        q.pop();
        for(int i = h[tp]; i != -1; i = nex[i]){
            int t = to[i];
            if(level[t] == -1 && cost[i]){
                level[t] = level[tp] + 1;
                q.push(t);
                if(t == T)return 1;
            }
        }
    }
    return 0;
}
int dfs(int u, int flow){
    if(u == T)return flow;
    int ret = flow, k;
    for(int i = h[u]; i != -1  && ret; i = nex[i]){
        int v = to[i];
        if(cost[i] != 0&& level[u]+1 == level[v]){
            k = dfs(v, min(cost[i], ret));
            if(!k)level[v] = -1;
            ret -= k;
            cost[i] -= k;
            cost[i^1] += k;
        }

    }
    return flow - ret;
}
int dinic(){
    int ans = 0, flow;
    while(bfs())
        while(flow = dfs(S, INF))
            ans += flow;
    return ans;
}

int main(){
    int t;
    scanf("%d", &t);
    int ca = 0;
    while(t--){
        cnt = 0;
        scanf("%d %d", &n, &m);
        memset(h, -1, sizeof h);
        int mm = -1, sum = 0;
        S = 0;
        for(int i = 1; i <= n; i++){
            int p, s, e;
            scanf("%d %d %d", &p, &s, &e);
            add(S, i, p);
            add(i, S, 0);
            mm = max(mm, e);
            sum += p;
            for(int j = s;j <= e; j++){
                add(i, n+j, 1);
                add(n+j, i, 0);
            }
        }
        int tp = n+mm+1;
        for(int i = n+1; i < tp; i++){
            add(i, tp, m);
            add(tp, i, 0);
        }
        T = tp;
        int res = dinic();
        printf("Case %d: ", ++ca);
        if(res == sum)puts("Yes");
        else puts("No");
        cout<<endl;


    }
return 0;
}

题目:Marriage Match II

题意: 有N个女孩要与N个男孩玩配对游戏.每个女孩有一个可选男孩的集合(即该女孩可以选自己集合中的任意一个男孩作为该轮的搭档).
然后从第一轮开始,每个女孩都要和一个不同的男孩配对.如果第一轮N个女孩都配对成功,那么就开始第二轮配对,女孩依然从自己的备选男孩集合中选择,但是不能选那些已经被该女孩在前几轮选择中选过的男孩了(比如i女孩在第一轮选了j男孩,那么i在第二轮就不能选j男孩了). 问你游戏最多能进行多少轮?
思路:本题就是用二分去枚举轮数,然后建立超级源点和超级汇点,跑网络流。
参考博客:HDU 3081 Marriage Match II(二分+并查集+最大流)
本题因为数组开小了,一直TE,TE到生无可恋。
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100100;//一定要开大点,一定开大点
const int INF = 1e7;
int cnt = 0, cost[maxn], h[maxn], to[maxn], nex[maxn];
int level[210], fa[210];
int dis[210][210];
int S, T, n, m;
inline void add(int x, int y, int z)
{
    cost[cnt] = z;
    to[cnt] = y;
    nex[cnt] = h[x];
    h[x]= cnt++;
}
inline int Find(int x)
{
    return fa[x] == -1 ? x : fa[x]=Find( fa[x] );
}
inline bool bfs()
{
    queue<int>q;
    memset(level,-1,sizeof(level));
    level[S] = 0;
    q.push(S);
    while(!q.empty())
    {
        int tp = q.front();
        q.pop();
        for(int i = h[tp]; i != -1; i = nex[i])
        {
            int t = to[i];
            if(level[t] == -1 && cost[i])
            {
                level[t] = level[tp] + 1;
                q.push(t);
                if(t == T)return 1;
            }
        }
    }
    return 0;
}
inline int dfs(int u, int flow)
{
    if(u == T)return flow;
    int ret = flow, k;
    for(int i = h[u]; i != -1  && ret; i = nex[i])
    {
        int v = to[i];
        if(cost[i] != 0 && level[u]+1 == level[v])
        {
            k = dfs(v, min(cost[i], ret));
            if(!k)level[v] = -1;
            ret -= k;
            cost[i] -= k;
            cost[i^1] += k;
        }

    }
    return flow - ret;
}
inline int dinic()
{
    int ans = 0, flow;
    while(bfs())
        while(flow = dfs(S, INF))
            ans += flow;
    return ans;
}
inline void init()
{
    memset(h, -1, sizeof h);
    cnt = 0;
}
inline bool check(int n, int mid)
{
    init();
    for(int i = 1; i <= n; i++)
    {
        for(int j = n+1; j <= n*2; j++)
        {
            if(dis[i][j])
            {
                add(i, j, 1);
                add(j, i, 0);
            }
        }
    }
    for(int i = 1; i <= n; i++)
    {
        add(S, i, mid);
        add(i, S, 0);
    }
    for(int i = n+1; i < T; i++)
    {
        add(i, T, mid);
        add(T, i, 0);
    }
    return dinic() == n*mid;
}
inline int bsearch_2(int l, int r, int n)
{
    while (l < r)
    {
        int mid = (1+r+l)>>1;
        if (check(n, mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}
int main()
{
    int t, f, u, v;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d %d %d", &n, &m, &f);
        memset(dis, 0, sizeof dis);
        memset(fa, -1, sizeof fa);
        for(int i = 1; i <= m; i++)
        {
            scanf("%d %d", &u, &v);
            dis[u][v+n] = 1;
        }
        for(int i = 1; i <= f; i++)
        {
            int fx, fy;
            scanf("%d %d", &u, &v);
            fx = Find(u);
            fy = Find(v);
            if(fx != fy)fa[fx] = fy;
        }
        for(int i = 1; i <= n; i++)
        {
            for(int j = i+1; j <= n; j++)
            {
                if(Find(i) == Find(j))
                {
                    for(int k = n+1; k <= 2*n; k++)
                    {
                        dis[i][k] = dis[j][k] = (dis[i][k] || dis[j][k]);
                    }
                }
            }
        }
        T = n*2+1;
        S = 0;
        int l = 0, r = n;
        int ans = bsearch_2(l, r, n);
        printf("%d\n", ans);
    }
    return 0;
}

题目:Dining

题意:一头牛可以选一杯喝的和食物,怎么使这个匹配最大。
思路:牛食物喝的匹配很容易想到二分图匹配,但是使这个匹配最大,所以就想到了最大流,但是如何建图呢,因为一个牛对应一个喝的和一份食物,所以我们想到把牛放中间,但是会存在一个问题,多个食物指向同一个牛,那么就不是我们想要的结果,所以就用到了拆点,把牛拆成两个点,这个使我们要的结果。
为什么拆点如图:
Refused
拆点之后:
Refused
代码:

//建图的思路 源点 >> 食物 >> 牛1 >> 牛11 >> 喝的 >> 汇点
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int level[maxn];
queue<int>q;
int S, T, n, m, d;
void add(int x, int y, int z){
     cost[cnt] = z;
     to[cnt] = y;
     nex[cnt] = h[x];
     h[x]= cnt++;

     cost[cnt] = 0;
     to[cnt] = x;
     nex[cnt] = h[y];
     h[y] = cnt++;
}

bool bfs(){
    queue<int>q;
    memset(level,-1,sizeof(level));
    level[S] = 0;
    q.push(S);
    while(!q.empty()){
        int tp = q.front();
        q.pop();
        for(int i = h[tp]; i != -1; i = nex[i]){
            int t = to[i];
            if(level[t] == -1 && cost[i]){
                level[t] = level[tp] + 1;
                q.push(t);
                if(t == T)return 1;
            }
        }
    }
    return 0;
}
int dfs(int u, int flow){
    if(u == T)return flow;
    int ret = flow, k;
    for(int i = h[u]; i != -1  && ret; i = nex[i]){
        int v = to[i];
        if(cost[i] != 0&& level[u]+1 == level[v]){
            k = dfs(v, min(cost[i], ret));
            if(!k)level[v] = -1;
            ret -= k;
            cost[i] -= k;
            cost[i^1] += k;
            //if(flow == 0)break;
        }

    }
    return flow - ret;
}
int dinic(){
    int ans = 0, flow;
    while(bfs())
        while(flow = dfs(S, INF))
            ans += flow;
    return ans;
}


int main(){
    while(~scanf("%d %d %d", &n, &m, &d)){
    memset(h, -1, sizeof h);
    S = 0;
    T = n*2+m+d+1;
    int k1, k2, v;
    for(int i = 1; i <= m; i++)add(S, i, 1);//
    for(int i = 1; i <= d; i++)add(n*2+m+i, T, 1);
    for(int i = 1; i <= n; i++)add(m+i, n+m+i, 1);
    for(int i = 1; i <= n; i++){
        scanf("%d %d", &k1, &k2);
        while(k1--){
            scanf("%d", &v);
            add(v, m+i, 1);
        }
        while(k2--){
            scanf("%d", &v);
            add(n+m+i, n*2+m+v, 1);
        }
    }

    printf("%d\n",dinic());
}
return 0;
}


题目:Food

思路:这题的思想跟上面的差不多,稍微改改就行了,建图的方法都是一样的。
代码:

//建图思路  食物->>人1->>人11->>喝的

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int level[maxn];
queue<int>q;
int S, T, n, m, d;
void add(int x, int y, int z)
{
    cost[cnt] = z;
    to[cnt] = y;
    nex[cnt] = h[x];
    h[x]= cnt++;

    cost[cnt] = 0;
    to[cnt] = x;
    nex[cnt] = h[y];
    h[y] = cnt++;
}

bool bfs()
{
    queue<int>q;
    memset(level,-1,sizeof(level));
    level[S] = 0;
    q.push(S);
    while(!q.empty())
    {
        int tp = q.front();
        q.pop();
        for(int i = h[tp]; i != -1; i = nex[i])
        {
            int t = to[i];
            if(level[t] == -1 && cost[i])
            {
                level[t] = level[tp] + 1;
                q.push(t);
                if(t == T)return 1;
            }
        }
    }
    return 0;
}
int dfs(int u, int flow)
{
    if(u == T)return flow;
    int ret = flow, k;
    for(int i = h[u]; i != -1  && ret; i = nex[i])
    {
        int v = to[i];
        if(cost[i] != 0&& level[u]+1 == level[v])
        {
            k = dfs(v, min(cost[i], ret));
            if(!k)level[v] = -1;
            ret -= k;
            cost[i] -= k;
            cost[i^1] += k;
            //if(flow == 0)break;
        }

    }
    return flow - ret;
}
int dinic()
{
    int ans = 0, flow;
    while(bfs())
        while(flow = dfs(S, INF))
            ans += flow;
    return ans;
}

char a[1000];
int main()
{
    while(~scanf("%d %d %d", &n, &m, &d))
    {
        memset(h, -1, sizeof h);
        S = 0;
        T = n*2+m+d+1;
        int v;
        for(int i = 1; i <= m; i++)
        {
            scanf("%d", &v);
            add(S, i, v);
        }
        for(int i = 1; i <= d; i++)
        {
            scanf("%d", &v);
            add(n*2+m+i, T, v);
        }
        for(int i = 1; i <= n; i++)add(m+i, n+m+i, 1);
        for(int i = 1; i <= n; i++)
        {
            scanf("%s", a);
            for(int j = 0; j < m; j++)
            {
                if(a[j] == 'Y')add(j+1, m+i,1);
            }
        }
        for(int i = 1; i <= n; i++)
        {
            scanf("%s", a);
            for(int j = 0; j < d; j++)
            {
                if(a[j] == 'Y')add(m+n+i,n*2+m+j+1, 1);
            }
        }

        printf("%d\n",dinic());
    }
    return 0;
}


题目:Marriage Match IV

题意:就是给你一个图,问你这个图最多有多少条最短路。
思路:我最开始的思路就是跑一个最小费用最大流,对这个模板进行稍微的修改,但是一直T,找不到原因,我感觉可能是每一次跑最可能会超时,所以我就换了一种思想就是先跑一个最短路,然后把能够成最短路的所有边建一个网络流,权值为1,跑一个最大流就是结果。
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int head[maxn], v[maxn], w[maxn], Next[maxn], d[maxn], vis[maxn];
int tot = 0;
int level[maxn];

int S, T, n, m;
void add(int x, int y, int z)
{
    cost[cnt] = z;
    to[cnt] = y;
    nex[cnt] = h[x];
    h[x]= cnt++;

    cost[cnt] = 0;
    to[cnt] = x;
    nex[cnt] = h[y];
    h[y] = cnt++;
}
void add1(int u, int v1, int val)
{
    v[tot] = v1;
    w[tot] = val;
    Next[tot] = head[u];
    head[u] = tot++;
}
inline int read()
{
    char ch = getchar();
    int x = 0, f = 1;
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while('0' <= ch && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
void spfa()//纯spfa()模板
{
    queue<int>q;
    memset(d, 0x3f3f3f3f, sizeof d);
    memset(vis, 0, sizeof vis);
    d[S] = 0;
    vis[S] = 1;
    q.push(S);
    while(q.size())
    {
        int x = q.front();
        q.pop();
        vis[x] = 0;
        for(int i = head[x]; ~i; i = Next[i])
        {
            int y = v[i], z = w[i];
            if(d[y] > d[x] + z)
            {
                d[y] = d[x] + z;
                if(!vis[y])q.push(y), vis[y] = 1;
            }
        }
    }
}
bool bfs()
{
    queue<int>q;
    memset(level,-1,sizeof(level));
    level[S] = 0;
    q.push(S);
    while(!q.empty())
    {
        int tp = q.front();
        q.pop();
        for(int i = h[tp]; i != -1; i = nex[i])
        {
            int t = to[i];
            if(level[t] == -1 && cost[i])
            {
                level[t] = level[tp] + 1;
                q.push(t);
                if(t == T)
                {
                    return 1;
                }
            }
        }
    }
    return 0;
}
int dfs(int u, int flow)
{
    if(u == T)return flow;
    int ret = flow, k;
    for(int i = h[u]; i != -1  && ret; i = nex[i])
    {
        int v = to[i];
        if(cost[i] != 0 && level[u]+1 == level[v])
        {
            k = dfs(v, min(cost[i], ret));
            if(!k)level[v] = -1;
            ret -= k;
            cost[i] -= k;
            cost[i^1] += k;
            //if(flow == 0)break;
        }

    }
    return flow - ret;
}
int dinic()//纯dinic模板,没有进行任何修改
{
    int ans = 0, flow;
    while(bfs())
    {
        while(flow = dfs(S, INF))
            ans += flow;
    }
    return ans;
}


int main()
{
    int a, b, c, t;
    t = read();
    while(t--)
    {
        memset(head, -1, sizeof head);
        memset(h, -1, sizeof h);
        cnt = 1;
        tot = 1;
        n = read();
        m = read();
        for(int i = 1; i <= m; i++)
        {
            a = read(), b = read(), c = read();//建图
            if(a == b)continue;
            add1(a, b, c);
        }
        S = read(), T = read();
        spfa();
        for(int i = 1; i <= n; i++)//找构成最短路的边
        {
            for(int j = head[i]; ~j; j = Next[j])
            {
                int k = v[j], z = w[j];
                if(d[k] == d[i] + z)
                {
                    add(i, k, 1);
                }
            }
        }
        printf("%d\n", dinic());
    }
    return 0;
}

最小费用最大流:

题目:P3381 【模板】最小费用最大流

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
const int maxn = 1e5+10;
const int INF  = 0x3f3f3f3f;
int ver[maxn], edge[maxn], cost[maxn], Next[maxn], head[maxn];
int d[N], incf[N], pre[N], v[N];
int n, k, tot, s, t, maxflow, ans;

void add(int x, int y, int z, int c){
     ver[++tot] = y;//
     edge[tot] = z;
     cost[tot] = c;
     Next[tot] = head[x];
     head[x] = tot;

     ver[++tot] = x;
     edge[tot] = 0;
     cost[tot] = -c;
     Next[tot] = head[y];
     head[y] = tot;
}

bool spfa(){
     queue<int>q;
     memset(d, INF, sizeof d);
     memset(v, 0, sizeof v);
     q.push(s);
     d[s] = 0;
     v[s] = 1;
     incf[s] = INF;
     while(q.size()){
        int x = q.front();
        v[x] = 0;
        q.pop();
        for(int i = head[x]; ~i; i = Next[i]){
            if(!edge[i])continue;
            int y = ver[i];
            if(d[y] > d[x] + cost[i]){
                d[y] = d[x] + cost[i];
                incf[y] = min(incf[x], edge[i]);
                pre[y] = i;
                if(!v[y])v[y] = 1, q.push(y);
            }
        }

     }
     if(d[t] == INF)return false;
     return true;
}

void update(){
     int x = t;
     while(x != s){
        int i = pre[x];
        edge[i] -= incf[t];
        edge[i^1] += incf[t];
        x = ver[i^1];
     }
     maxflow += incf[t];
     ans += d[t]*incf[t];
}
int main(){
    int a, b, c, d;
    memset(head, -1, sizeof head);
    scanf("%d %d %d %d", &n, &k, &s, &t);
    tot = 1;
    for(int i = 1; i <= k; i++){
        scanf("%d %d %d %d", &a, &b, &c, &d);
        add(a, b, c, d);
    }
    while(spfa())update();
    printf("%d %d\n",maxflow, ans);
return 0;
}

题目:Going Home

思路:就是建图,然后跑最小费用最大流。
代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;;
const int maxn = 1e6+10;
const int INF  = 0x3f3f3f3f;
int ver[maxn], edge[maxn], cost[maxn], Next[maxn], head[maxn];
int d[N], incf[N], pre[N], v[N];
int n, k, tot, s, t, maxflow, ans;
char str[105][105];
vector<pair<int, int> >h, m;
void add(int x, int y, int z, int c)
{
    ver[++tot] = y;//
    edge[tot] = z;
    cost[tot] = c;
    Next[tot] = head[x];
    head[x] = tot;

    ver[++tot] = x;
    edge[tot] = 0;
    cost[tot] = -c;
    Next[tot] = head[y];
    head[y] = tot;
}

bool spfa()
{
    queue<int>q;
    memset(d, INF, sizeof d);
    memset(v, 0, sizeof v);
    q.push(s);
    d[s] = 0;
    v[s] = 1;
    incf[s] = INF;

    while(q.size())
    {
        int x = q.front();
        v[x] = 0;
        //cout<<x<<endl;
        q.pop();
        for(int i = head[x]; ~i; i = Next[i])
        {
            if(!edge[i])continue;
            int y = ver[i];
            if(d[y] > d[x] + cost[i])
            {
                d[y] = d[x] + cost[i];
                incf[y] = min(incf[x], edge[i]);
                pre[y] = i;
                if(!v[y])v[y] = 1, q.push(y);
            }
        }

    }
    if(d[t] == INF)return false;
    return true;
}

void update()
{
    int x = t;
    while(x != s)
    {
        int i = pre[x];
        edge[i] -= incf[t];
        edge[i^1] += incf[t];
        x = ver[i^1];
    }
    maxflow += incf[t];
    ans += d[t]*incf[t];
}
int num(int i, int j)
{
    return (i-1)*n+j;
}
int distance(int x1, int y1, int x2, int y2)
{
    return abs(x1-x2)+abs(y1-y2);
}
int main()
{
    int a, b, c, d;
    while(scanf("%d %d", &n, &k) && n && k)
    {

        memset(head, -1, sizeof head);
        h.clear();
        m.clear();
        tot = 1, ans = 0, maxflow = 0;
        getchar();
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= k; j++)
            {
                scanf("%c", &str[i][j]);
            }
            getchar();
        }

        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= k; j++)
            {
                if(str[i][j] == 'H')h.push_back(make_pair(i, j));
                if(str[i][j] == 'm')m.push_back(make_pair(i, j));
            }
        }
        s = 0;

        int x1, y1, x2, y2;
        int len = m.size();
        t = m.size()*h.size()+1;
        for(int i = 0; i < m.size(); i++)
        {
            for(int j = 0; j < h.size(); j++)
            {
                x1 = m[i].first, y1 = m[i].second;
                x2 = h[j].first, y2 = h[j].second;
                int v = distance(x1, y1, x2, y2);
                add(i+1,j+1+len, 1, v);
            }
            add(s, i+1, 1, 0);
        }
        for(int i = 0; i < h.size(); i++)
        {
            add(i+1+len, t, 1, 0);
        }
        while(spfa())update();
        printf("%d\n",ans);
    }

    return 0;
}

题目:Farm Tour

注意:该题是双向图。
代码:

#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
const int N = 5010;
const int maxn = 1e5+10;
const int INF  = 0x3f3f3f3f;
int ver[maxn], edge[maxn], cost[maxn], Next[maxn], head[maxn];
int d[N], incf[N], pre[N], v[N];
int n, k, tot, s, t, maxflow, ans;

void add(int x, int y, int z, int c)
{
    ver[++tot] = y;//
    edge[tot] = z;
    cost[tot] = c;
    Next[tot] = head[x];
    head[x] = tot;

    ver[++tot] = x;
    edge[tot] = 0;
    cost[tot] = -c;
    Next[tot] = head[y];
    head[y] = tot;
}

bool spfa()
{
    queue<int>q;
    memset(d, INF, sizeof d);
    memset(v, 0, sizeof v);
    q.push(s);
    d[s] = 0;
    v[s] = 1;
    incf[s] = INF;

    while(q.size())
    {
        int x = q.front();
        v[x] = 0;
        q.pop();
        for(int i = head[x]; ~i; i = Next[i])
        {
            if(!edge[i])continue;
            int y = ver[i];
            if(d[y] > d[x] + cost[i])
            {
                d[y] = d[x] + cost[i];
                incf[y] = min(incf[x], edge[i]);
                pre[y] = i;
                if(!v[y])v[y] = 1, q.push(y);
            }
        }

    }
    if(d[t] == INF)return false;
    return true;
}

void update()
{
    int x = t;
    while(x != s)
    {
        int i = pre[x];
        edge[i] -= incf[t];
        edge[i^1] += incf[t];
        x = ver[i^1];
    }
    maxflow += incf[t];
    ans += d[t]*incf[t];
}

int main()
{
    int a, b, c;
    while(~scanf("%d %d", &n, &k))
    {
        memset(head, -1, sizeof head);
        tot = 1;
        s = n+1;
        t = n+2;
        ans = 0;
        maxflow =  0;
        for(int i = 1; i <= k; i++)
        {
            scanf("%d %d %d", &a, &b, &c);
            add(a, b, 1,c);
            add(b, a, 1, c);
        }
        add(s, 1, 2, 0);
        add(n, t, 2, 0);
        while(spfa())update();

        printf("%d\n",ans);

    }
    return 0;
}

题目:Minimum Cost

代码:

#include<string.h>
#include<iostream>
#include<stdio.h>
#include<queue>
#include<math.h>
#include<algorithm>
#include<vector>

using namespace std;
const int N = 100;
const int maxn = 1e4+10;
const int INF  = 0x3f3f3f3f;
int ver[maxn], edge[maxn], cost[maxn], Next[maxn], head[maxn];
int d[N], incf[N], pre[N], v[N];
int n, k, tot, s, t, maxflow, ans, m;
int shoper[N][N], supply[N][N];
int mpa[N][N][N];
int need1[N], need2[N];

void add(int x, int y, int z, int c)
{
    ver[++tot] = y;//
    edge[tot] = z;
    cost[tot] = c;
    Next[tot] = head[x];
    head[x] = tot;

    ver[++tot] = x;
    edge[tot] = 0;
    cost[tot] = -c;
    Next[tot] = head[y];
    head[y] = tot;
}

bool spfa()
{
    queue<int>q;
    memset(d, INF, sizeof d);
    memset(v, 0, sizeof v);
    q.push(s);
    d[s] = 0;
    v[s] = 1;
    incf[s] = INF;

    while(q.size())
    {
        int x = q.front();
        v[x] = 0;
        //cout<<x<<endl;
        q.pop();
        for(int i = head[x]; ~i; i = Next[i])
        {
            if(!edge[i])continue;
            int y = ver[i];
            if(d[y] > d[x] + cost[i])
            {
                d[y] = d[x] + cost[i];
                incf[y] = min(incf[x], edge[i]);
                pre[y] = i;
                if(!v[y])v[y] = 1, q.push(y);
            }
        }

    }
    if(d[t] == INF)return false;
    return true;
}

void update()
{
    int x = t;
    while(x != s)
    {
        int i = pre[x];
        edge[i] -= incf[t];
        edge[i^1] += incf[t];
        x = ver[i^1];
    }
    maxflow += incf[t];
    ans += d[t]*incf[t];
}
int num(int i, int j)
{
    return (i-1)*n+j;
}
int distance(int x1, int y1, int x2, int y2)
{
    return abs(x1-x2)+abs(y1-y2);
}
int main()
{


    while(scanf("%d%d%d", &n, &m, &k), n != 0 || m != 0 || k != 0)
    {
        memset(need1, 0, sizeof need1);
        memset(need2, 0, sizeof need2);
        s = 0;
        t = n+m+1;
        memset(head, -1, sizeof head);
        tot = 1, ans = 0;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= k; j++)
            {
                scanf("%d", &shoper[i][j]);
                need1[j] += shoper[i][j];
            }

        for(int i = 1; i <= m; i++)
            for(int j = 1; j <= k; j++)
            {
                scanf("%d", &supply[i][j]);
                need2[j] += supply[i][j];
            }

        int f = 1;
        for(int i = 1; i <= n; i++)
            if(need1[i] > need2[i])
                f = 0;

        for(int i = 1; i <= k; i++)
            for(int j = 1; j <= n; j++)
                for(int l = 1; l <= m; l++)
                    scanf("%d", &mpa[i][j][l]);


        if(f == 0) printf("-1\n");
        else
        {
            for(int l = 1; l <= k; l++)
            {
                for(int i = 1; i <= m; i++)
                    add(0, i, supply[i][l], 0);
                for(int i = m + 1; i <= m + n; i++)
                    add(i, m + n + 1, shoper[i-m][l], 0);

                for(int i = 1; i <= m; i++)
                    for(int j = m + 1; j <= m + n; j++)
                        add(i, j, shoper[j-m][l], mpa[l][j-m][i]);

                while(spfa())update();
                memset(head, -1, sizeof head);
                tot = 1;

            }
            printf("%d\n", ans);
        }
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值