题意: n个插座,下面n行是每个插座的类型
m个电器,下面m行每行两个单词分别是电器的名字和插头类型
k个转换器,下面k行每行两个单词,分别表示转换器的入口类型和插头类型
每种转换器的个数是无限的,可以多个转换器相连。 求最小不能插上去的电器的数量。
分析:
最大流。
定义源点和汇点,源点和设备相连,容量为1.
汇点和插头相连,容量也为1.
插头和设备相连,容量也为1.
可转换插头相连,容量也为inf(因为插头有无限个) 其实我使用Floyd求出设备可以连哪些插座,加一条cap为1的边。(这样建图略麻烦)
因为大量使用stl 这题用了60ms。后面还用了c++11的特性。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
#define INF 0x7fffffff
const int maxn = 1e3+10;
struct Edge{
int to , cap,rev; // rev反向边
};
vector<Edge>G[maxn];
int level[maxn],iter[maxn]; // 顶点到源点的标号 当前弧
void add_edge(int from,int to,int cap) //cap容量
{
G[from].push_back((Edge){to,cap,G[to].size()});
G[to].push_back((Edge){from,0,G[from].size()-1 });
}
void bfs(int s) // 分层
{
memset(level,-1,sizeof(level));
queue<int>que;
level[s] = 0;
que.push(s);
while(!que.empty())
{
int v = que.front();que.pop();
for(int i = 0; i < G[v].size(); i++)
{
Edge &e = G[v][i];
if (e.cap>0 && level[e.to] < 0)
{
level[e.to] = level[v]+1;
que.push(e.to);
}
}
}
}
int dfs(int v, int t, int f) //寻增广路
{
if (v==t) return f;
for(int &i = iter[v]; i < G[v].size(); i++)
{
Edge &e = G[v][i];
if (e.cap > 0 && level[v] < level[e.to])
{
int d = dfs(e.to , t, min(f,e.cap));
if (d > 0)
{
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t) // s到t最大流
{
int flow = 0;
for(;;)
{
bfs(s);
if (level[t] < 0) return flow;
memset(iter,0,sizeof(iter));
int f;
while((f = dfs(s,t,INF)) > 0) { flow += f;}
}
}
map<string, int> IDT;
set<string> plug;
map<string, int> device;
bool f[maxn][maxn];
string s1,s2;
int main(){
#ifdef LOCAL
freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
//freopen("output.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
int T,n,m,kase = 0;
cin>>T;
while(T--)
{
IDT.clear(); plug.clear();device.clear();
memset(f,false,sizeof(f));
if (kase) cout<<endl;
kase++;
cin>>n;
for(int i = 1; i <= n; i++)
{
cin>>s1;
plug.insert(s1);
IDT[s1] = IDT.size() - 1;
}
cin>>m;
for(int i = 1; i <= m; i++)
{
cin>>s1>>s2;
device[s2]++;
if (IDT.count(s2)==0) IDT[s2] = IDT.size() - 1;
}
int s = 0,t = n+m+1;
for(int i= 0; i <= n+m+1; i++) G[i].clear();
for (int i = 1; i <= m; i++) add_edge(s,i,1);
for (int i = 1+m; i < 1+m+n; i++) add_edge(i,t,1);
int k;
cin>>k;
for (int i = 0; i < k; i++)
{
cin>>s1>>s2;
if (IDT.count(s1) == 0) IDT[s1] = IDT.size() - 1;
if (IDT.count(s2) == 0) IDT[s2] = IDT.size() - 1;
f[IDT[s1]][IDT[s2]] = 1;
}
int N = IDT.size();
for (int i = 0; i < N ; i++) f[i][i] = 1;
for (int kk = 0; kk < N ; kk++)
for (int i = 0; i < N ; i++)
for (int j = 0; j < N ; j++)
f[i][j] = f[i][j] || (f[i][kk] && f[kk][j]);
int idx = 1;
for (auto i: device)
{
vector<int> v;
int num = IDT[i.first];
if (plug.count(i.first)) v.push_back(IDT[i.first] + m + 1);
for (int j = 0; j < N; j++)
if (j != num && f[num][j] && j < n) v.push_back(j + m + 1);
for (int j = 0; j < i.second; idx++, j++)
for (auto kk: v) add_edge(idx, kk,1);
}
cout<<m-max_flow(s,t)<<endl;
}
return 0;
}