链接:

http://poj.org/problem?id=1087

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82835#problem/C

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88230#problem/J (密码:0817)

 

 

n个插座,m个电器及其对应的插座,k个转化器,前一个插座可以转化为后一个插座,问最少有多少设备没有插座用,转换器数量不限
最大流,源点向插座建边,容量为1,电器向汇点建边,容量为1,相应的插座和电器连边,容量为1,前一个插座转化为后一个插座,
后一个插座向前一个插座建边,容量为无穷大,求得的最大流即为最多配对的电器。

 

网络流的部分是会了, 可是如何建图还是要学习

 

 

代码:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

#define N 1005
#define INF 0xfffffff

int G[N][N], Layer[N];
char s[N][50];

bool CanLine(char s1[], char s2[]) ///判断转接口是否相同
{
    if(strcmp(s1, s2)==0)
        return true;
    return false;
}

bool BFS(int Start, int End)
{
    queue<int>Q;
    Q.push(Start);

    memset(Layer, -1, sizeof(Layer));
    Layer[Start] = 0;

    while(Q.size())
    {
        int u = Q.front();
        Q.pop();

        if(u==End) return true;

        for(int i=1; i<=End; i++)
        {
            if(Layer[i]==-1 && G[u][i])
            {
                Layer[i] = Layer[u] + 1;
                Q.push(i);
            }
        }
    }
    return false;
}
int DFS(int u, int MaxFlow, int End)
{
    if(u==End) return MaxFlow;

    int uflow = 0;

    for(int i=1; i<=End; i++)
    {
        if(G[u][i] && Layer[i]==Layer[u]+1)
        {
            int flow = min(G[u][i], MaxFlow-uflow);
            flow = DFS(i, flow, End);

            G[u][i] -= flow;
            G[i][u] += flow;
            uflow += flow;

            if(uflow == MaxFlow) break;
        }
    }

    return uflow;
}
int Dinic(int Start, int End)
{
    int MaxFlow = 0;

    while(BFS(Start, End))
        MaxFlow += DFS(Start, INF, End);

    return MaxFlow;
}


int main()
{
    int n, m, k;

    while(scanf("%d", &n)!=EOF)
    {
        int i, j;

        memset(G, 0, sizeof(G));

        for(i=1; i<=n; i++) ///插头从1~n
            scanf("%s", s[i]);

        scanf("%d", &m);
        for(i=1; i<=m; i++) ///手机从n~n+m, 忽略手机的名字
            scanf("%*s%s", s[i+n]);

        scanf("%d", &k);

        ///Ki是转换头进入的开始点, Kj是转换头出去的开始点, Start是源点,End是汇点
        int Ki = n+m, Kj = Ki+k, Start = Kj+k+1, End = Start+1;
        for(i=1; i<=k; i++) ///转换器的进入n+m~n+m+k, 转换器的出从n+m+k~n+m+2*k
        {
            ///把入和出连接
            scanf("%s%s", s[Ki+i], s[Kj+i]);
            G[Ki+i][Kj+i] = INF; ///转换器无限提供
        }

        for(i=1; i<=m; i++) ///建立手机和转换器,插座的关系
        {
            for(j=1; j<=n; j++) ///匹配一下手机和插座是否直接可以相连
                if(CanLine(s[i+n], s[j]))
                    G[i+n][j]=true;

            for(j=1; j<=k; j++) ///匹配一下手机和转换器入是否可以相连
                if(CanLine(s[i+n], s[Ki+j]))
                    G[i+n][Ki+j]=true;
        }

        for(i=1; i<=k; i++) ///建立转换器与转换器,插座的关系
        {
            for(j=1; j<=k; j++) /// 匹配转换器与转换器入,转换器无限提供, 直接最大值
                if(i!=j && CanLine(s[Kj+i], s[Ki+j]))
                    G[Kj+i][Ki+j] = INF;

            for(j=1; j<=n; j++) /// 匹配转换器出和插座的关系
                if(CanLine(s[Kj+i], s[j])==true)
                    G[Kj+i][j] = true;
        }

        for(i=1; i<=m; i++) ///源点与手机的关系
            G[Start][n+i] = true;

        for(i=1; i<=n; i++) ///插座与汇点的关系
            G[i][End] = true;

        printf("%d\n", m-Dinic(Start, End));
    }

    return 0;
}

 

posted on 2015-08-17 21:33  栀蓝  阅读(160)  评论(0编辑  收藏  举报

levels of contents