题目概述
一间屋子里有N种插座,每种插座有唯一的名称,且数量只有一个,在这个屋里可能会要使用M种电器,每种电器名称也是唯一,而且也只有一个,需要一种插座,市面上有K种插座适配器,其需要一个插座,同时也提供一个插座,数量不限,问最少有多少电器会因没有插座无法使用
某些电器需要的插座可能屋里根本没有
时限
1000ms/3000ms
输入
第一行整数N,其后N行,每行一个字符串,代表一种现有插座的名称,下一行整数M,其后M行,每行两个字符串,电器名称和需要的插座名称,下一行整数K,其后K行,每行两个字符串,为适配器提供的插座和需要的插座,输入只有一组
限制
1<=N,M,K<=100;1<=字符串长度<=24;字符串只含字母和数字
输出
一个数,为所求最少无法使用数
样例输入
4
A
B
C
D
5
laptop B
phone C
pager B
clock B
comb X
3
B X
X A
X D
样例输出
1
讨论
图论,网络流,最大流,Isap+gap优化,原题有点长,有些信息就显得很隐蔽,构图不难,源点,电器,插座,汇点,除了适配器以外其他边残量都是1,适配器则是从一种插座到另一种插座连边,残量无穷大,基本就是这样
实现方面,先说输出,问的是有多少没电的,所以要用M减掉最大流量,其次,数据范围,原有插座100,电器100,够了?不够,如果所有电器需要的插座都不存在呢,又是100,所以需要300才够,字符串处理用map映射string到int即可
谁能告诉额为啥梳子需要插电……
题解状态
624K,32MS,C++,1894B
题解代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<iostream>
#include<string>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 304
#define memset0(a) memset(a,0,sizeof(a))
int N, M, K, index, S, T = 301;//原有插座数 电器数 适配器种类 每个节点分配的编号 源点 汇点 汇点不是301 后面重新赋值了
map<string, int>plugs;//记录所有节点的编号
int R[MAXN][MAXN], dis[MAXN], from[MAXN], gap[MAXN];//最大流四数组 残量矩阵 层次 父节点 每个层次的节点数
string name1, name2;//用于临时存放字符串
queue<int>q;
int fun()
{
for (int p = 0; p < N; p++) {
cin >> name1;//input
plugs[name1] = ++index;//先为插座分配编号 没有构图 因为不知道M和K的值不便于分配汇点编号
}
scanf("%d", &M);//input//感谢cin的输入流同步 即便混用也不会出错
for (int p = 0; p < M; p++) {
cin >> name1 >> name2;//input
R[S][plugs[name1] = ++index] = 1;//源点到电器 残量1
if (plugs.find(name2) == plugs.end())
R[plugs[name1]][plugs[name2] = ++index] = 1;//对不存在的插座要额外读入map 这是从电器到插座的边
else
R[plugs[name1]][plugs[name2]] = 1;
}
scanf("%d", &K);//input
for (int p = 0; p < K; p++) {
cin >> name1 >> name2;//input
R[plugs[name1]][plugs[name2]] = INF;//适配器的插座到插座流量无穷 因为有无限供应
}
T = (++index)++;//为汇点分配编号 这里index和以前题里的N一样
for (int p = 1; p <= N; p++)
R[p][T] = 1;//插座到汇点的边 由于最先读入 因此一定在这个范围内 注意电器带来的新插座类型不能连到汇点 因为他们并不存在
for (int p = 0; p < index; p++)//往后就是常用的isap算法了 不多解释了
dis[p] = index;
gap[dis[T] = 0]++;
q.push(T);
while (!q.empty()) {
int a = q.front();
q.pop();
for (int p = 0; p < index; p++)
if (dis[p] == index&&R[p][a]) {
q.push(p);
gap[dis[p] = dis[a] + 1]++;
}
}
int most = 0, p = S, flow = INF;
while (dis[S] < index) {
int i;
for (i = 0; i < index && (!R[p][i] || dis[p] != dis[i] + 1); i++);
if (i != index) {
from[i] = p;
flow = min(flow, R[p][i]);
p = i;
if (p == T) {
while (p != S) {
i = from[p];
R[i][p] -= flow;
R[p][i] += flow;
p = i;
}
most += flow;
flow = INF;
}
}
else {
if (!--gap[dis[p]])
break;
dis[p] = index;
for (int i = 0; i < index; i++)
if (R[p][i] && dis[p] > dis[i] + 1)
dis[p] = dis[i] + 1;
gap[dis[p]]++;
if (p != S)
p = from[p];
}
}
return M - most;//不要想错 这里返回的是M减最大流量
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);
scanf("%d", &N);//input
printf("%d\n", fun());//output
}
EOF