poj1087 - A Plug for UNIX

133 篇文章 0 订阅

                                  想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410
                                  转载请注明出处:http://blog.csdn.net/wangjian8006

题目大意:这题题目意思实在太难懂,不过题目意思搞清楚之后还是比较好做的
在这个题目里有两种物品,一个是插座,一个是电器
插座只有一个插孔和一个插头,电器只有一个插头
首先有n种插座,n种插座用字符串表示,这n种插座可以理解为是插在电源上的插座
然后有m个电器,现在电器要充电,电器用字符串表示,每个电器都有自己可以插的插座
(这个插座可以不是那n个插在电源上的插座,可以是其他的插座)
现在有k个信息
s1 s2代表s1插座可以插到s2插座上去,这里类似于将插头转换了一下
这些s1与s2也可以不是那n个插在电源上的插座

给出这些个信息问你还有多少个电器没有插座可以用


解题思路:
很容易联想到最大流,这样建图:
建一个源点,指向所有电器,容量为1
所有电器指向他们可以插的那个插头上,容量为1
如果一个插头可以插到另一个插头,那么将s1指向s2,容量为无限大
将所有插在电源上的插头指向汇点,容量为1

然后从源点到汇点求最大流即可
不过建图会比较复杂,因为涉及到字符串的处理,所以用map容器比较好做点

 

/*
Memory 2800K
Time    47MS
*/
#include <iostream>
#include <string>
#include <map>
#include <queue>
using namespace std;
#define MAXV 810				//最大值设为400贡献了RE一次
#define INF INT_MAX
#define min(a,b) (a>b?b:a)

map<string,int> rec_dev;
char str[30],stmp[30];
int rec_dev_sum;
int res[MAXV][MAXV];			//保存图的信息
int n,m,k;
int	dis[MAXV];
int source,sink,maxflow;

int bfs(){
	int k;
	queue<int> q;
    memset(dis,-1,sizeof(dis));
    dis[sink]=0;
	
    q.push(sink);
    while(!q.empty()){
		k=q.front();
		q.pop();
        for(int i=0;i<MAXV;i++){
            if(dis[i]==-1 && res[i][k]){
                dis[i] = dis[k] + 1;
                q.push(i);
            }
        }
        if(k==source) return 1;
    }
	return 0;
}

int dfs(int cur,int cp){
    if(cur==sink)	return cp;
	
    int tmp=cp,t;
    for(int i=0;i<MAXV && tmp;i++){
        if(dis[i]+1==dis[cur] && res[cur][i]){
            t=dfs(i,min(res[cur][i],tmp));
            res[cur][i]-=t;
            res[i][cur]+=t;
            tmp-=t;
        }
    }
    return cp-tmp;
}

void dinic(){					//dinic不用解释了
    maxflow=0;
    while(bfs()) maxflow+=dfs(source,INF);
}

int main(){
	int i;
	while(~scanf("%d",&n)){
		memset(res,0,sizeof(res));
		rec_dev.clear();
		rec_dev_sum=1;
		source=0;sink=MAXV-1;

		for(i=0;i<n;i++){
			scanf("%s",str);
			rec_dev[str]=rec_dev_sum++;
			res[rec_dev[str]][sink]=1;			//插在电源的插座指向汇点
		}

		scanf("%d",&m);
		for(i=0;i<m;i++){
			scanf("%s%s",stmp,str);
			rec_dev[stmp]=rec_dev_sum++;
			if(!rec_dev[str]){					//如果这个插座不存在就要新加进来
				rec_dev[str]=rec_dev_sum++;
			}

			res[source][rec_dev[stmp]]=1;			//源点指向设备
			res[rec_dev[stmp]][rec_dev[str]]=1;		//设备指向插座
		}

		scanf("%d",&k);
		for(i=0;i<k;i++){
			scanf("%s%s",str,stmp);
			if(!rec_dev[str]){					//如果插座不存在就要新加进来
				rec_dev[str]=rec_dev_sum++;
			}
			if(!rec_dev[stmp]){
				rec_dev[stmp]=rec_dev_sum++;
			}
			res[rec_dev[str]][rec_dev[stmp]]=INF;	//插座对插座是无限
		}

		dinic();
		printf("%d\n",m-maxflow);
	}
	return 0;
}


 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值