网络流解决Unix Plug问题

分析题目的时候注意到从最初的插座经过适配器再到最终的电器设备是一条路径,这条路径由插销连接到一起,题目中最后似乎要求能够得到多少条类似的路径。由此可以想到通过网络流解决。

网络流解决问题的关键是判断出图节点表达什么意思,路径表达什么意思。

每个路径都有一个源点和终点,可以把路径看成是电线,而节点看成是电线尽头是什么插座。

网络流算法需要求增广路径,在填充流,注意在一个方向填充流的时候要在相反方向上减少该流。

#include<iostream>

#include<vector>

#include<map>

#include<string>

#define INF 99999

#define MAXNUM 420

using namespace std;

 

map<string,int> names;

int cap[MAXNUM][MAXNUM];

int flow[MAXNUM][MAXNUM];

int n;

int m;

int k;

int maxid;

int id = 2;

bool mark[1001];

vector<int> pathlist;

 

void getPair(pair<string,int>& tmp);

void input();

void slove();

int findpath(int from);

void init();

int remain(int i,int j){

return cap[i][j] - flow[i][j];

}

int main(){

init();

input();

slove();

}

void init(){

int i,j;

for(i=0;i<MAXNUM;i++)

for(j=0;j<MAXNUM;j++){

cap[i][j] = 0;

flow[i][j] = 0;

}

}

int findpath(int from){

int i;

if(mark[from] == false){

mark[from] = true;

for(i=1;i<=maxid;i++){

if(flow[from][i] < cap[from][i]){

if(i == 2){

pathlist.push_back(i);

pathlist.push_back(from);

return 1;

}else{

if(findpath(i)){

pathlist.push_back(from);

return 1;

}

}

}

}

}

return 0;

}

void slove(){

int i,len,comp;

memset(mark,false,1001);

while(findpath(1)){

len = pathlist.end() - pathlist.begin();

comp = remain(pathlist[len-1],pathlist[len-2]);

for(i=len-1;i>1;i--){

if(comp > remain(pathlist[i-1],pathlist[i-2]))

comp = remain(pathlist[i-1],pathlist[i-2]);

}

for(i=len;i>1;i--){

flow[pathlist[i-1]][pathlist[i-2]] += comp;

flow[pathlist[i-2]][pathlist[i-1]] -= comp;

}

pathlist.clear();

memset(mark,false,1001);

}

for(i=1,comp=0;i<=maxid;i++)

comp += flow[1][i];

cout<<m-comp<<endl;

}

void getPair(pair<string,int>& tmp){

map<string,int>::iterator pNames;

if((pNames=names.find(tmp.first)) == names.end()){

tmp.second = ++id;

names.insert(tmp);

}else

tmp = *pNames;

}

void input(){

int i,j,l;

pair<string,int> tmp;

cin>>n;

for(i=0;i<n;i++){

cin >> tmp.first;

getPair(tmp);

cap[1][tmp.second]++;

}

cin>>m;

for(i=0;i<m;i++){

cin >> tmp.first >> tmp.first;

getPair(tmp);

cap[tmp.second][2]++;

}

cin>>k;

for(i=0;i<k;i++){

cin>>tmp.first;

getPair(tmp);

j = tmp.second;

cin>>tmp.first;

getPair(tmp);

l = tmp.second;

cap[l][j] = INF;

}

maxid = id;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值