紫书例题11-7 UNIX插头 (A Plug for UNIX)

题意:n个插座,m个设备,k个转换器。现在你要把这些设备插到插座上,每个设备都有对应的插头类型,使用转换器就可以“转化”插头类型。转化器的数量是无限提供的,就是插头类型可以任意转化。现在问你最少剩多少个不匹配的设备。
分析:n个插座,m个设备,两两匹配,我们不难想到这是类似于一个二分图的结构。让我们把n个出现的插座连上超级源点,但多于n的插座(会有多的)不能连上源点。再把设备连上汇点.再把插座类型连上设备。
最后,就是设备之间是可以相互转化的。我们使用最短路算法floyd求一下各个点之间的连通性。得到一个连通性数组
G[i][j],表示i设备可以转化为j设备.然后i和j之间连一条INF的边,代表可以任意转化.
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000;
const int INF = 1e9+5;
struct Edge{
int from,to,cap,flow;
};
struct Dicnic {
int n,m,s,t;
vector edge;vector G[maxn];
bool vis[maxn];int d[maxn],cur[maxn];
void init(int n){
for(int i=0;i<n;i++) G[i].clear();
edge.clear();
}
void addedge(int from,int to,int cap){
edge.push_back((Edge){ from,to,cap,0});
edge.push_back((Edge){ to,from,0,0});
m=edge.size();
G[from].push_back(m-2);G[to].push_back(m-1);
}
bool bfs(){
memset(vis,0,sizeof(vis));
queue Q;Q.push(s);d[s]=0;vis[s]=1;
while(!Q.empty()){
int x=Q.front();Q.pop();
for(int i=0;i<G[x].size();i++){
Edge &e=edge[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;d[e.to]=d[x]+1;
Q.push(e.to);
if(e.tot) return 1;
}
}
}
return vis[t];
}
long long dfs(int x,long long a){
if(xt||a0) return a;
long long flow=0,f;int i;
for( i=cur[x];i<G[x].size();i++){
cur[x]=i;
Edge &e=edge[G[x][i]];
if(d[x]+1d[e.to]&&(f=dfs(e.to,min(a,(long long)e.cap-(long long)e.flow)))>0){
e.flow+=f;
edge[G[x][i]^1].flow-=f;
flow+=f;a-=f;
if(a==0) break;
}
}
return flow;
}
long long Maxflow(int s,int t){
this->s=s;this->t=t;
long long flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}

};
map<string,int> mp;int cnt=0;
int id(const string & s){
if(mp.count(s)) return mp[s];
else return mp[s]=(++cnt);
}
Dicnic D;bool G[maxn][maxn];
int target[maxn],device[maxn];
int main(){
int T;cin>>T;
while(T–){
int n;cin>>n;
mp.clear();cnt=0;
for(int i=0;i<n;i++){
string s;cin>>s;
target[i]=id(s);
}
int m;scanf("%d",&m);
for(int i=0;i<m;i++){
string s1,s2;
cin>>s1>>s2;
device[i]=id(s2);
}
int k;scanf("%d",&k);
memset(G,0,sizeof(G));
for(int i=0;i<k;i++){
string s1,s2;cin>>s1>>s2;
G[id(s2)][id(s1)]=true;
}
//Floyd
int nn=mp.size();
for(int K=1;K<=nn;K++){
for(int i=1;i<=nn;i++){
for(int j=1;j<=nn;j++){
G[i][j]|=(G[i][K]&&G[K][j]);
}
}
}
int s=0,t=m+n+15;
D.init(nn+m+100);
for(int i=1;i<=n;i++){
D.addedge(s,i,1);
}
for(int i=0;i<m;i++){
D.addedge(nn+i+1,t,1);
D.addedge(device[i],i+nn+1,1);
}
for(int i=1;i<=nn;i++){
for(int j=1;j<=nn;j++){
if(i==j) continue;
if(G[i][j]) D.addedge(i,j,INF);
}
}
long long ans=D.Maxflow(s,t);
cout<<m-ans<<endl;
if(T) cout<<endl;
}
return 0;}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minato_yukina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值