您的位置:首页 > 其它

【最大流 && 映射】POJ - 1087 A Plug for UNIX

2017-09-25 19:57 417 查看
Problem Description

输入n代表插排上有n个插口。接下来输入n行,每行输入一个字符串代表属于什么类型插口。

输入nn代表有nn个电器。接下来nn行,每行输入两个字符串,代表第一个字符串这个电器 可以 插到第二个字符串这种插口。

输入m代表有m种转换器,转换器个数不限,接下来输入m行,每行输入两个字符串,代表可以将第二个字符串的插口转换为第一个字符串这种插口类型。

思路:

核心就是读懂题目,问了学长题目什么意思才懂的。然后把字符串都映射成点,建图,求最大流就好了。答案是nn-最大流。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#include<iostream>
using namespace std;
struct node
{
int to, w, next;
};
node Map[50000];
int head[500], vis[500], cnt;
void add(int u, int v, int w)//前向星存图
{
Map[cnt].to = v;
Map[cnt].w = w;
Map[cnt].next = head[u];
head[u] = cnt++;
Map[cnt].to = u;
Map[cnt].w = 0;
Map[cnt].next = head[v];
head[v] = cnt++;
}
int dfs(int s, int e, int f)//找增广路,找到返回限制流量,找不到返回0
{
vis[s] = 1;
if(s == e) return f;
for(int i = head[s]; ~i; i = Map[i].next)
{
int to = Map[i].to, &w = Map[i].w;
if(!vis[to] && w)
{
int d = dfs(to, e, min(f, w));
if(d > 0)
{
w -= d;
Map[i^1].w += d;
return d;
}
}
}
return 0;

}
int ek(int s, int e)//最大流
{
int Max_flow = 0, flow = 0;
for(;;)
{
memset(vis, 0, sizeof(vis));
flow = dfs(s, e, 0x3f3f3f3f);
if(flow == 0) break;
Max_flow += flow;
}
return Max_flow;
}
int main()
{
int n, i, m, nn;
string s, str;
while(~scanf("%d", &n))
{
cnt = 0;
int top = 1;
memset(head, -1, sizeof(head));
map<string, int> q;
map<string, int>::iterator it;
for(i = 1; i <= n; i++)
{
cin >> s;
q[s] = top++;
}
scanf("%d", &nn);
for(i = 1; i <= nn; i++)
{
cin >> str >> s;
if(!q.count(str))
q[str] = top++;
if(!q.count(s))
q[s] = top++;
add(q[str], q[s], 1);//用电器和插口类型建边,流量为1
add(0, q[str], 1);//超级源点和用电器建边,流量为1
}
scanf("%d", &m);
while(m--)
{
cin >> str >> s;//转换器可以将s类型的插口变为str类型
if(!q.count(str))
q[str] = top++;
if(!q.count(s))
q[s] = top++;
add(q[str], q[s], 0x3f3f3f3f);//str类型插口和s类型插口建边,流量为无穷(无穷多个)
}
for(i = 1; i <= n; i++)
{
add(i, i+top-1, 1);//插口和插口建边,流量为1,毕竟插口只有一个
add(i+top-1, n+top, 1);//插口和超级汇点建边流量为1
}
printf("%d\n", nn - ek(0, n + top));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: