poj1087(网络流 + EK)
来源:互联网 发布:足球数据库哪个好 编辑:程序博客网 时间:2024/04/28 15:59
题目链接:http://poj.org/problem?id=1087
题意:房间里N个通了电的插座,有M种电器,每种电器只有插在对应类型的插座上才能正常工作。现在有K个转换器,能将一种类型的插座转换成另一种类型的插座。利用这K个转换器和N个通电插座,使尽量多的电器能够正常通电工作(题目要求输出最少能使多少台电器不工作的数目)。
思路:网络流求最大流(能正常工作的电器数目的最大值)。
建图过程:在源点与N个通电插座之间建立一条边,权值为该类型插座的数目个数
在转换器能转换的两个类型插座之间建立一条边,权值为INF(无限多)
在电器与汇点之间建立一条权值为1的边。
后来发现我建的图和网上通常建的图刚好是一个逆向图,不知道他们是怎么想的,反正我在做这个题的时候是这样想的建图的,不过两种见图的方式最后的结果都是一样的。
注意:1.每种转换器的数目由无数多个,所以权值应该为INF
2.注意在输入电器的时候出现的新型插座和输入转换器时候的新型插座一定要加入到插座类型plug中,我因为一时偷懒,没有处理输入转换器的时候出现的新型插座导致比赛的时候,这个题是没有AC的,忘后来者记住。
代码:
#include<stdio.h>#include<string.h>#define INF 1000000char plug[250][30];char dev[30],nee[30];char adapter[30],plu[30];int cap[505][505],flow[505][505];int dis[505];int que[505],pre[505]; int min(int x,int y) { return x<y ? x : y; } int EK(int t) { int i,temp; int ans=0; int head=0,tail=0; memset(flow,0,sizeof(flow)); while(1) { memset(pre,0,sizeof(pre)); memset(dis,0,sizeof(dis)); dis[0]=INF; que[tail]=0; tail++; pre[0]=0; while(head != tail) { temp=que[head]; head++; if(head == 505) head = 0; for(i=0;i<=t;i++) { if(!dis[i] && flow[temp][i] < cap[temp][i]) { dis[i] = min(dis[temp],cap[temp][i]-flow[temp][i]); pre[i]=temp; que[tail]=i; tail++; if(tail == 505) tail = 0; } } } if(dis[t] == 0) break; for(i=t;i!=0;i=pre[i]) { flow[pre[i]][i] += dis[t]; flow[i][pre[i]] -= dis[t]; } ans += dis[t]; } return ans; } int main(){int i,j;int N,M,K,t;int minnum;memset(cap,0,sizeof(cap)); scanf("%d",&N);for(i=1;i<=N;i++){scanf("%s",plug[i]);if(i==1)cap[0][i] = 1;else{for(j=1;j<i;j++){if(strcmp(plug[i],plug[j]) == 0){cap[0][j] += 1; //一个类型的插座有几个,与源点连边的权值就为几break;}}if(j == i)cap[0][j] = 1;}}scanf("%d",&M);t = 401+M;for(i=401;i<=401+M-1;i++){/*为什么从401开始呢,因为N如果有100种,而M得时候又有100种新型的,到K得时候可能出现200种新型的,所以总共插座类型的话可能有400种,所以电器只能从401开始*/ scanf("%s%s",dev,nee);cap[i][t] = 1;//在电器与汇点之间建立一条权值为1的边for(j=1;j<=N;j++){if(strcmp(nee,plug[j]) == 0){cap[j][i] = 1;break;}}if(j == N+1)//出现新型的插座类型,则加入plug中{N++;strcpy(plug[N],nee);cap[j][i] = 1;}}scanf("%d",&K);while(K--){scanf("%s%s",adapter,plu); for(i=1;i<=N;i++){if( strcmp(plug[i],plu) == 0 )break;}if(i == N+1)//出现新型的插座类型,则加入plug中{N++;strcpy(plug[N],plu);}for(j=1;j<=N;j++){if( strcmp(plug[j],adapter) == 0 )break;}if(j == N+1)//出现新型的插座类型,则加入plug中{N++;strcpy(plug[N],adapter);}cap[i][j] = INF;//如果plug[j]可以由plug[i]转化而来,则从i连接一条权值为INF的边到j} minnum = M-EK(t); printf("%d\n",minnum);return 0;}
- poj1087(网络流 + EK)
- poj1087 网络最大流
- 【网络流】poj1087
- poj1087解题报告(最大流 EK算法)
- 网络流EK算法
- 网络流EK算法
- POJ1149_PIGS(网络流/EK)
- 网络流EK算法
- 网络流---EK模版
- 网络流EK算法
- 网络流EK算法
- 网络流-EK
- 网络流(EK)
- 网络流--EK算法
- POJ1087(网络流,二分图匹配)
- 【网络流】:poj1087,A Plug for UNIX
- poj1273(网络流基础+EK)
- 网络流EK算法理解
- POJ 3169(带起点的拆分约束)
- php函数返回引用
- Android 游戏与应用开发最佳学习路线图
- 各种排序算法分析总结
- 建立ARM交叉编译环境 (arm-none-linux-gnueabi-gcc with EABI)
- poj1087(网络流 + EK)
- sscanf函数的用法
- 一步一步学JBPM(4)--JBPM和SSH2结合使用jar包详解
- Linux日志管理
- 用python做网页抓取与解析入门笔记
- 嵌入python的c++程序发布(一)最简单的方法
- CentOS添加epel和rpm-fusion源
- PB中对SQL SERVER 2K 数据库的创建、备份与恢复
- 算法导论2.1插入排序