POJ-1087 A Plug for UNIX(網絡最大流)

題目鏈接:POJ-1087 A Plug for UNIX

You are in charge of setting up the press room for the inaugural meeting of the United Nations Internet eXecutive (UNIX), which has an international mandate to make the free flow of information and ideas on the Internet as cumbersome and bureaucratic as possible.
Since the room was designed to accommodate reporters and journalists from around the world, it is equipped with electrical receptacles to suit the different shapes of plugs and voltages used by appliances in all of the countries that existed when the room was built. Unfortunately, the room was built many years ago when reporters used very few electric and electronic devices and is equipped with only one receptacle of each type. These days, like everyone else, reporters require many such devices to do their jobs: laptops, cell phones, tape recorders, pagers, coffee pots, microwave ovens, blow dryers, curling
irons, tooth brushes, etc. Naturally, many of these devices can operate on batteries, but since the meeting is likely to be long and tedious, you want to be able to plug in as many as you can.
Before the meeting begins, you gather up all the devices that the reporters would like to use, and attempt to set them up. You notice that some of the devices use plugs for which there is no receptacle. You wonder if these devices are from countries that didn’t exist when the room was built. For some receptacles, there are several devices that use the corresponding plug. For other receptacles, there are no devices that use the corresponding plug.
In order to try to solve the problem you visit a nearby parts supply store. The store sells adapters that allow one type of plug to be used in a different type of outlet. Moreover, adapters are allowed to be plugged into other adapters. The store does not have adapters for all possible combinations of plugs and receptacles, but there is essentially an unlimited supply of the ones they do have.

Input

The input will consist of one case. The first line contains a single positive integer n (1 <= n <= 100) indicating the number of receptacles in the room. The next n lines list the receptacle types found in the room. Each receptacle type consists of a string of at most 24 alphanumeric characters. The next line contains a single positive integer m (1 <= m <= 100) indicating the number of devices you would like to plug in. Each of the next m lines lists the name of a device followed by the type of plug it uses (which is identical to the type of receptacle it requires). A device name is a string of at most 24 alphanumeric
characters. No two devices will have exactly the same name. The plug type is separated from the device name by a space. The next line contains a single positive integer k (1 <= k <= 100) indicating the number of different varieties of adapters that are available. Each of the next k lines describes a variety of adapter, giving the type of receptacle provided by the adapter, followed by a space, followed by the type of plug.

Output

A line containing a single non-negative integer indicating the smallest number of devices that cannot be plugged in.

Sample Input

4
A
B
C
D
5
laptop B
phone C
pager B
clock B
comb X
3
B X
X A
X D

Sample Output

1


題意:

有n個不同型號的插座(每種型號只有1個),m個不同的用電器且有着對應的插座型號(不同用電器對應的插座型號可能相同),同時有k種插座替代關係,例如A型號插座可以替代B型號插座(但B不一定能替代A)(插座型號和用電器均用字符串表示)。
問最少有多少用電器沒有插座用?

輸入一個整數n,接下來n行爲現有的插座型號;
再輸入一個整數m,接下來m行爲用電器和插座的對應關係(用電器 對應插座);
在輸入一個整數k,接下來k行爲插座間的替代關係(A B 表示 B可以代替A)。


分析:

網絡流首先就是要建圖了,以樣例輸入爲例,可以得到以下的圖。(僅標出了正向邊,反向邊均爲0)
在這裏插入圖片描述
這個要注意的點(坑)挺多的;

  1. 首先要明確現有的插座只有一開始輸入的那n種插座,並且每種只有1個;
  2. 在後續輸入的對應和替代關係中,出現的插座都不一定是現有的;
  3. 替換關係是單向的,但是是可以傳遞的,例如輸入了 X A 和 B X,同時說明A可以替代B,而且可能會存在多個個可以替代B的,所以替代關係的正向邊的容量應當爲INF
  4. 因爲不知道一共會有多少不同型號的插座,所以不便於按順序編號,於是可以使用map直接將字符串映射爲編號,然後建圖。
  5. 注意數組大小,稍微開大些。

建完圖以後就是套最大流的板子了。


以下代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<algorithm>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e3+50;
const int maxm=1e5+50;
struct edge
{
    int w;
    int to;
    int next;
}e[maxm];
int head[maxn],cnt;
int s=0,t=maxn-1;
int n,m,k;
void addedge(int u,int v,int w)
{
    e[cnt].w=w;
    e[cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
    cnt++;
}
int dis[maxn];     //dis數組記錄層次
bool bfs()         //利用BFS建立分成圖,從而可以多次DFS增廣
{
	memset(dis,-1,sizeof(dis));     //初始化dis數組
	queue<int> q;
	q.push(s);
	dis[s]=0;      //源點層次爲0
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];i!=-1;i=e[i].next)
		{
			int v=e[i].to;
			if(e[i].w>0&&dis[v]==-1)     //可達&&未分層
			{
				dis[v]=dis[u]+1;         //分層
				if(v==t)                 //若到達匯點,則分層結束,返回true
					return true;
				q.push(v);
			}
		}
	}
	return false;  //運行到此處,說明匯點已不可達,返回false
}
int cur[maxn];     //弧優化:cur數組用於記錄上一次DFS增廣時u已經增廣到第幾條邊,從而優化時間
int dfs(int u,int flow)       //flow代表流入u點的最大流量
{
	if(u==t)
		return flow;          //到達匯點,直接返回flow
	for(int &i=cur[u];i!=-1;i=e[i].next)
	{                         //注意i前面用&引用,這樣就可以直接改變cur[u]
		int v=e[i].to;
		if(dis[v]==dis[u]+1&&e[i].w>0)   //v爲u的下一層&&可達
		{
			int k=dfs(v,min(flow,e[i].w));
			if(k>0)
			{
				e[i].w-=k;         //正向邊-=k
				e[i^1].w+=k;       //反向邊+=k
				return k;
			}
		}
	}
	return 0;       //無法繼續增廣,返回0
}
int dinic()
{
	int ans=0;      //記錄總流量
	while(bfs())    //分層
	{
		for(int i=0;i<maxn;i++)    //初始化cur數組,即將head數組賦給cur數組
			 cur[i]=head[i];
		while(int k=dfs(s,INF))    //增廣
			ans+=k;
	}
	return ans;
}
int main()
{
    memset(head,-1,sizeof(head));
    cnt=0;
    scanf("%d",&n);
    map<string,int> mp;        //映射編號
    string a,b;
    int index=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a;
        mp[a]=++index;
        addedge(s,index,1);     //連接插座和源點
        addedge(index,s,0);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b;
        mp[a]=++index;
        if(!mp.count(b))
            mp[b]=++index;
        addedge(mp[b],mp[a],1);    //連接插座和用電器
        addedge(mp[a],mp[b],0);
        addedge(mp[a],t,1);        //連接用電器和匯點
        addedge(t,mp[a],0);
    }
    scanf("%d",&k);
    for(int i=1;i<=k;i++)
    {
        cin>>a>>b;
        if(!mp.count(a))
            mp[a]=++index;
        if(!mp.count(b))
            mp[b]=++index;
        addedge(mp[b],mp[a],INF);   //建立替代關係
        addedge(mp[a],mp[b],0);
    }
    printf("%d\n",m-dinic());
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章