POJ 1087 网络流

题意

有N个电源适配器,M个电器,K种配对方案,一种电源适配器可以配对另一种电源适配器。求最多能适配多少个电器。

题解

网络流最重要的就是建图啦。这道题的话,建图的时候搭配map那是相当的方便。适配器和超级源点相连,电器和终点相连。超级源点到适配器的边容量为1,电器到超级终点的边容量为1。建好图后,扔到Dinic算法里就行了。

注意事项

一定要注意网络流的方向!!!!

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<iostream>
#include<queue>
#include<map>
#define MAXN 1010
#define INF 1e9
using namespace std;

struct Edge{
    int from,to,cap,flow;
};

struct Dinic{
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> g[MAXN];
    bool vis[MAXN];
    int d[MAXN];
    int cur[MAXN];

    void init(int n){
        this->n=n;
        edges.clear();
        for(int i=0;i<=n;i++)
            g[i].clear();
    }

    void addEdge(int from,int to,int cap){
        edges.push_back((Edge){from,to,cap,0});
        edges.push_back((Edge){to,from,0,0});
        m=edges.size();
        g[from].push_back(m-2);
        g[to].push_back(m-1);
    }

    bool bfs(){
        memset(vis,0,sizeof(vis));
        memset(d,-1,sizeof(d));
        queue<int> q;
        q.push(s);
        d[s]=0;
        vis[s]=true;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=0;i<g[x].size();i++){
                Edge e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=true;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }


    int dfs(int x,int a){
        if(x==t||a==0)
            return a;
        int flow=0,f;
        for(int& i=cur[x];i<g[x].size();i++){
            Edge& e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)
                    break;

            }
        }
        return flow;
    }

    int maxFlow(int s,int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
            memset(cur,0,sizeof(cur));
            flow+=dfs(s,INF);
        }
        return flow;
    }
};

map<string,int> mp;
int main(){
    Dinic d;

    string str,str1,str2;
    int st=0;
    int tar=1;
    int tot=2;
    d.init(1005);

    int p;
    scanf("%d",&p);
    for(int i=0;i<p;i++){
        cin>>str;
        if(mp[str]==0)
            mp[str]=tot++;
        d.addEdge(st,mp[str],1);
    }

    int m;
    scanf("%d",&m);
    for(int i=0;i<m;i++){
        cin>>str1>>str2;
        if(mp[str1]==0)
            mp[str1]=tot++;
        if(mp[str2]==0)
            mp[str2]=tot++;
        d.addEdge(mp[str1],tar,1);
        d.addEdge(mp[str2],mp[str1],1);
    }
    int k;
    scanf("%d",&k);
    for(int i=0;i<k;i++){
        cin>>str1>>str2;
        if(mp[str1]==0)
            mp[str1]=tot++;
        if(mp[str2]==0)
            mp[str2]=tot++;
        d.addEdge(mp[str2],mp[str1],INF);
    }
    printf("%d\n",m-d.maxFlow(st,tar));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值