POJ1087A Plug for UNIX(会议室的插座)——最大流

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

题目描述:
现在由你负责布置Internet 联合组织首席执行官就职新闻发布会的会议室。
由于会议室修建时被设计成容纳全世界各地的新闻记者,因此会议室提供了多种电源插座用
以满足(会议室修建时期)各国不同插头的类型和电压。不幸的是,会议室是很多年前修建的,
那时新闻记者很少使用电子设备,所以会议室对每种插座只提供了一个。新闻发布会时,新闻记
者需要使用许多电子设备,如手提电脑,麦克风,录音机,传呼机等等。尽管这些设备很多可以
使用电池,但是由于发布会时间很长并且是单调乏味的,记者们希望能够使用尽可能多的设备(这
些设备需要使用插座),以打发时间。
在发布会之前,你收集了记者们使用的设备的信息,开始布置会议室。你注意到有些设备的
插头没有合适的插座可用。你怀疑这些设备来自那些在修建会议室时不存在的国家。对有些插座
来说,有多个设备的插头可以使用。而对另一些插座来说,没有哪些设备的插头可以用得上。
为了试图解决这个问题,你光顾了附近的商店,商店出售转换器,这些转换器可以将一种插
头转换成另一种插头。而且转换器可以串联。商店没有足够多的转换器类型,满足所有的插头和
插座的组合,但对于已有某种转换器,总是可以提供无限多个。

输入描述:
输入文件包含多个测试数据。输入文件的第一行为一个整数N,然后隔一个空行之后是N 个
输入块,每个输入块对应一个测试数据。输入块之间用空行隔开。每个输入块格式为:
每个输入块的第一行为一个正整数n,1≤n≤100,表示会议室提供的插座个数;接下来n
行列出了会议室提供的n 个插座,每个插座用一个数字字母式字符串描述(至多有24 个字符);
接下来一行为一个正整数m,1≤m≤100,表示待插入的设备个数;接下来m 行中,每行首
先是设备的名称,然后是它使用的插头的名称;插头的名称跟它所使用的插座的名称是一样的;
设备名称是一个至多包含24 个字母数字式字符的字符串;任何两个设备的名称都不同;设备名称
和插头之间用空格隔开;
接下来一行为一个正整数k,1≤k≤100,表明可以使用的转换器种数;接下来的k 行,每行
描述了一种转换器:首先是转换器提供的插座类型,中间是一个空格,然后是插头的类型。

输出描述:
对输入文件中的每个测试数据,输出一个非负整数,表明至少有多少个设备无法插入。

顶多有200个插座,100个设备。源点到各个设备建一条cap为1的边,各个插座到汇点建一条cap为1的边,各个设备到匹配的插座建一条cap为1的边,插座之间的转换建一条cap为INF的边,求最大流

ISAP Memory: 336K Time: 32MS

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
#include<string>
const int maxn=400;
const int INF=0x3f3f3f3f;
using namespace std;
int n,s,t;
struct Edge{
    int from,to,cap,flow;
    Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
vector<Edge> edges;
vector<int> G[maxn];
int gap[maxn],d[maxn],cur[maxn],p[maxn];
inline void addedge(int u,int v,int c){
    edges.push_back(Edge(u,v,c,0));
    edges.push_back(Edge(v,u,0,0));
    int m=edges.size();
    G[u].push_back(m-2);
    G[v].push_back(m-1);
}
int ISAP(){
    memset(cur,0,sizeof(cur));
    memset(d,0,sizeof(d));
    memset(gap,0,sizeof(gap));
    int x=s,flow=0,a=INF;
    while(d[s]<n){
        if(x==t){
            flow+=a;
            while(x!=s){
                edges[p[x]].flow+=a;
                edges[p[x]^1].flow-=a;
                x=edges[p[x]].from;
            }
            a=INF;
        }
        int ok=0;
        for(int i=cur[x];i<G[x].size();++i){
            Edge& e=edges[G[x][i]];
            if(e.cap>e.flow&&d[e.to]+1==d[x]){
                p[e.to]=G[x][i];
                cur[x]=i;
                x=e.to;
                ok=1;
                a=min(a,e.cap-e.flow);
                break;
            }
        }
        if(!ok){
            int m=n;
            for(int i=0;i<G[x].size();++i){
                Edge& e =edges[G[x][i]];
                if(e.cap>e.flow) m=min(m,d[e.to]);
            }
            if(--gap[d[x]]==0) break;
            gap[d[x]=m+1]++;
            cur[x]=0;
            if(x!=s) x=edges[p[x]].from;
        }
    }
    return flow;
}
map<string,int> rec;
map<string,int> dev;
int N,M,K,cnt,cmt;
void Init(){
    cnt=0,cmt=200;
    s=302,t=303;
    cin>>N;
    for(int i=0;i<N;++i){
        string s;cin>>s;
        if(!rec.count(s)) rec[s]=++cnt;
        addedge(rec[s],t,1);
    }
    cin>>M;
    for(int i=0;i<M;++i){
        string s1,s2;cin>>s1>>s2;
        dev[s1]=++cmt;
        if(!rec.count(s2)) rec[s2]=++cnt;
        addedge(dev[s1],rec[s2],1);
        addedge(s,dev[s1],1);
    }
    cin>>K;
    for(int i=0;i<K;++i){
        string s1,s2;cin>>s1>>s2;
        if(!rec.count(s1)) rec[s1]=++cnt;
        if(!rec.count(s2)) rec[s2]=++cnt;
        addedge(rec[s1],rec[s2],INF);
    }
    n=cnt+cmt-200+2;
}
int main()
{
    Init();
    printf("%d\n",M-ISAP());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值