POJ1087 A Plug for UNIX(map+dinic最大流)

链接:http://poj.org/problem?id=1087
这题题意读懂了以后就好做了。
题意:
输入n,后面是n个插座。输入m,后面是m个电器,以及他们使用的插座名字
输入k,后面是k种转换器,表示前面的那个插座可以通过转换器转换到后面的插座。
问:最少有几个电器没有插座。
很容易想明白,这是一个最大流问题。建立一个源点和汇点,源点到每种插座的权值是这种插座被几个电器使用。只有最开始输入的n种插座能向汇点连边,因为全部插座就是一开始的n种,而且每种插座到汇点的权值是这种插座的数量。
k个转换器就是在插座之间连边就行了,权值是m,因为可以无限转换。然后就是一个最大流模型,dinic解决。这题的麻烦之处在于,输入都是用字符串操作,所以我用了一个map来记录编号,操作编号即可。答案是最少有几个电器没有插座,答案就是:总电器数-最多有几个电器有插座。

#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<iostream>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<stack>
#include<cctype>
#include<set>
#include<algorithm>
using namespace std;
const int INF=1e9+7;
typedef pair<int,int> pii;
typedef long long ll;
map<string,int> id;
int n,m,idcnt,st,ed;
int a[410],tot[410],pic[410][410],d[410],cnt[410];
//a数组是记录输入的n个插座的编号
//tot数组记录有几个电器用到了这个插座
//d数组在BFS的时候记录距离
//cnt数组记录在输入的n个插座中每种分别有几个
int ID(string a){//记录编号
    if(id.count(a))return id[a];
    return id[a]=++idcnt;
}
void build(){
    st=0;ed=idcnt+1;
    for(int i=1;i<=idcnt;i++){
        pic[st][i]=tot[i];
    }
    for(int i=1;i<=n;i++){
        pic[a[i]][ed]=cnt[a[i]];
    }
}
bool BFS(){
    queue<int> Q;
    memset(d,-1,sizeof d);
    d[st]=0;Q.push(st);
    while(!Q.empty()){
        int s=Q.front();Q.pop();
        for(int i=1;i<=ed;i++){
            if(pic[s][i]>0&&d[i]<0){
                d[i]=d[s]+1;Q.push(i);
            }
        }
    }
    return d[ed]>0;
}
int DFS(int s,int t,int flow){
    if(s==t||flow==0)return flow;
    int ans=0;
    for(int i=1;i<=ed;i++){
        if(d[i]==d[s]+1&&pic[s][i]>0){
            int ff=DFS(i,t,min(flow,pic[s][i]));
            if(ff>0){
                pic[s][i]-=ff;
                pic[i][s]+=ff;
                ans+=ff;
                flow-=ff;
                if(!flow)break;
            }
        }
    }
    if(!ans)d[s]=-1;
    return ans;
}
void dinic(){
    int ans=0;
    while(BFS()){
        ans+=DFS(st,ed,INF);
    }
    printf("%d\n",m-ans);//答案是m-ans
}
int main(){
// freopen("D://input.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        idcnt=0;id.clear();
        memset(a,0,sizeof a);
        memset(cnt,0,sizeof cnt);
        memset(pic,0,sizeof pic);
        memset(tot,0,sizeof tot);
        for(int i=1;i<=n;i++){
            string x;cin>>x;
            int now=ID(x);
            a[i]=now;cnt[now]++;//记录编号,同时记录这种插座有几个
        }
        scanf("%d",&m);
        for(int i=0;i<m;i++){
            string x,y;cin>>x>>y;
            tot[ID(y)]++;//记录这种插座有几个人用
        }
        int change;scanf("%d",&change);
        for(int i=1;i<=change;i++){
            string x,y;cin>>x>>y;
            pic[ID(x)][ID(y)]=m;//相互转换
        }
        build();
        dinic();
    }
    return 0;
}

你可能感兴趣的:(POJ1087 A Plug for UNIX(map+dinic最大流))