您的位置:首页 > 理论基础 > 计算机网络

POJ 1087 ZOJ 1157 插头和插座 网络流 繁琐 不喜欢

2013-04-27 20:09 363 查看
这个题的做法我已经知道,就是先构造出图,用网络流算法走个最大流,由于只有插头插座两种,也可以用二分图(二部图)匹配,但是要我写代码,感觉很烦躁,拖了很久,终于用网络流A了它。

记录第一次用map,呵呵。因为老是要做查找操作,所以试试map,希望能省点时间。

构图方式如下:

加入超源点s和超收点t

s点到所有插座的容量为1(因为该插座只有一个)

设备要用的插头到t点的容量为该类型插头的个数(例如有3个设备是B插头,插头B到t的容量为3)

插头能直接插在插座上(名字相同),那么插座到插头的容量为无穷。

插头能通过交换器连接到插座上,该插座到插头的容量也为无穷,用最大流算法求出能输送多少到超收点。

再用设备数-该值即为所求。

先贴POJ上能过的较繁琐,但是可能更直观的代码:

View Code

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <queue>
using namespace std;
#define MAXN  400
#define INF 0x7fffffff
#define min(a,b) a<b?a:b
map<string,int>mp;//原插座转换器
map<string,int>dev;
bool edge[MAXN][MAXN];//原插座+转换器的邻接矩阵
int ss,tt;//源点和汇点
int n,m;
int cur,ser;//原插座+设备的数目
int resi[MAXN][MAXN];  //容量网络
char a[MAXN][30];//存转换器中的插头插座名字
void init1()//读入会议室提供的插座和设备所需插座
{
int i;
map<string,int>::iterator it;
memset(resi,0,sizeof(resi));
scanf("%d",&n);
for(i=0; i<n; ++i)
{
cin>>a[i];
mp[a[i]] = i;
}
ss = n;
tt = n+1;
scanf("%d",&m);
cur = n+1;
for(i=0; i<m; ++i)
{
string d,dname;
cin>>dname>>d;
it = dev.find(d);
if(it != dev.end())
++resi[(*it).second][tt];
else
{
dev[d] = ++cur;
resi[cur][tt] = 1;
}
}
for(int i=0; i<n; ++i)
{
resi[ss][i] = 1;
string s = a[i];
it = dev.find(s);
if(it != dev.end())
resi[i][(*it).second] = INF;
}
}
void init2()//读入转换器的情况,构造出转换的邻接矩阵
{
int k;
map<string,int>::iterator it1,it2;
scanf("%d",&k);
memset(edge,0,sizeof(edge));
ser = n-1;
while(k--)
{
string s1,s2;
cin>>s2>>s1;
int id1,id2;
it1 = mp.find(s1);
if(it1 == mp.end())
{
mp[s1] = ++ser;
strcpy(a[ser],s1.c_str());
id1 = ser;
}
else
id1 = (*it1).second;
it2 = mp.find(s2);
if(it2 == mp.end())
{
mp[s2] = ++ser;
strcpy(a[ser],s2.c_str());
id2 = ser;
}
else
id2 = (*it2).second;
edge[id1][id2] = 1;
}
}
void init3()//如果v设备插的插座可以由u转来,那么resi[u][v] = INF
{
queue<int>Q;
map<string,int>::iterator it;
for(int i=0; i<n; ++i)
{
Q.push(i);
while(!Q.empty())
{
int u = Q.front();
Q.pop();
for(int j=0; j<=ser; ++j)
{
if(edge[u][j] == 1)
{
Q.push(j);
string s = a[j];
it = dev.find(s);
if(it != dev.end())
resi[i][(*it).second] = INF;
}
}
}
}
}
void pushRelabel()
{
queue<int>act;
int ef[MAXN],h[MAXN];
int i;
int sum = 0;
int u,p;
memset(ef,0,sizeof(ef));
memset(h,0,sizeof(h));
h[ss] = cur+1;
ef[ss] = INF;
ef[tt] = -INF;
act.push(ss);
while(!act.empty())
{
u =act.front();
act.pop();
for(i=0; i<=cur; ++i)
{
p = min(resi[u][i],ef[u]);
if(p>0 &&(u == ss || h[u] == h[i]+1))
{
resi[u][i] -= p;
resi[i][u] += p;
ef[u] -= p;
ef[i] += p;
if(i == tt)
sum += p;
if(i != ss && i != tt)
act.push(i);
}
}
if(u != ss && u != tt && ef[u] >0)
{
++h[u];
act.push(u);
}
}
printf("%d\n",m-sum);
}
int main()
{
//    freopen("in.cpp","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
mp.clear();
dev.clear();
init1();
init2();
init3();
pushRelabel();
if(T != 0)
puts("");
}
return 0;
}


代码的长度也有所减少啊
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: