pku3436 ACM Computer Factory 最大流

本文介绍了一道关于最大流算法的编程题,通过实例讲解了如何建立图模型,并使用BFS实现Ford-Fulkerson算法求解最大流问题。分享了手动模拟队列的方法,强调了图论题解的关键在于正确建图。

http://acm.pku.edu.cn/JudgeOnline/problem?id=3436

题目大意:每个电脑需要P个组成部分,现有N的机器,每个机器都可以对电脑进行加工,不过加工的前提是某些部分已经存在。且每个机器的加工都有一个performance,要求能得到的最大performance.

算法分析:最大流,没用到一点优化,依然不会sap,dinic,直接bfs()搞定的,不过这次的bfs(),我没有用STL,而是手动模拟了一下,又学习到一个好的模拟队列方法,不用更新队列,直接更新长度,将值都放在同一个数组里存着,按顺序出队就行了。继续努力!

总结一点:做图论题,关键就在建图,找到建图方法,只要有模板,并且熟悉,就能很快解决了。做题时,不要过早放弃,多想想,别太早就去翻标程,这样不容易达到锻炼思维,锻炼自己分析问题,快速建图的目的。

 

ContractedBlock.gif ExpandedBlockStart.gif 代码

   
#include < stdio.h >
#include
< string .h >
#define INF 0xfffffff
int perf[ 55 ], f[ 55 ][ 15 ];
int c[ 55 ][ 55 ], g[ 55 ][ 15 ], cc[ 55 ][ 55 ];
int pre[ 55 ];
int P, N;

int Min( int a, int b){ return a < b ? a : b;}
/* 这题关键是在建图,可以拆点,也可以不拆点,我采用的是不拆点,直接增加一个源点0和一个汇点N + 1,
所有input specification 不含1的机器都可以和源点相连,output specification全是1的都指向汇点
*/
void CreatGraph()
{
int i, j, k, flag;
memset(c,
0 , sizeof (c));
for (i = 1 ; i <= N; i ++ ){
for (j = 1 ; j <= N; j ++ ){
flag
= 0 ;
for (k = 1 ; k <= P; k ++ ){
if (i != j && g[i][k] + f[j][k] == 1 ){
flag
= 1 ;
}
}
if ( ! flag) c[i][j] = Min(perf[i], perf[j]);
}
}
for (i = 1 ; i <= N; i ++ ){
flag
= 0 ;
for (j = 1 ; j <= P; j ++ ){
if (f[i][j] == 1 )
flag
= 1 ;
}
if ( ! flag) c[ 0 ][i] = perf[i];
flag
= 0 ;
for (j = 1 ; j <= P; j ++ ){
if (g[i][j] == 0 )
flag
= 1 ;
}
if ( ! flag) c[i][N + 1 ] = perf[i];
}
}

int bfs()
{
int visit[ 55 ];
int num = 1 ;
int i, j, min, cur;
int que[ 55 ];
que[
0 ] = 0 ;
memset(pre,
- 1 , sizeof (pre));
memset(visit,
0 , sizeof (visit));
visit[
0 ] = 1 ;

min
= INF;
/* 这种模拟队列的方法很不错,将所有节点都只放到一个数组里,
不用更新队列,只更新队列的长度,并不断将点往后加就行了
*/
for (i = 0 ; i < num; i ++ ){
cur
= que[i];
for (j = 0 ; j <= N + 1 ; j ++ ){
if ( ! visit[j] && c[cur][j] > 0 ){
if (c[cur][j] < min)
min
= c[cur][j];
visit[j]
= 1 ;
que[num
++ ] = j;
pre[j]
= cur;

if (j == N + 1 )
break ;
}
}
if (j <= N + 1 )
break ;
}

if (i >= num)
return - 1 ;
else
return min;
}
void Ford_Fulkerson()
{
int f, t, tt, i, j, cnt;
int maxflow = 0 ;
int index = 0 ;

memcpy(cc, c,
sizeof (c));
while ((f = bfs()) != - 1 ){
maxflow
+= f;
t
= N + 1 ;
while (t != 0 ){
tt
= pre[t];
c[tt][t]
-= f;
c[t][tt]
+= f;
t
= tt;
}
}

cnt
= 0 ;
for (i = 1 ; i <= N; i ++ ){
for (j = 1 ; j <= N; j ++ ){
if (cc[i][j] - c[i][j] > 0 )
cnt
++ ;
}
}

printf(
" %d %d\n " , maxflow, cnt);
for (i = 1 ; i <= N; i ++ ){
for (j = 1 ; j <= N; j ++ ){
if (cc[i][j] - c[i][j] > 0 ){
printf(
" %d %d %d\n " , i, j, cc[i][j] - c[i][j]);
}
}
}
}
int main()
{
int i, j;
while (scanf( " %d%d " , & P, & N) != EOF){
memset(perf,
0 , sizeof (perf));
for (i = 1 ; i <= N; i ++ ){
scanf(
" %d " , & perf[i]);
for (j = 1 ; j <= P; j ++ ){
scanf(
" %d " , & f[i][j]);
}
for (j = 1 ; j <= P; j ++ ){
scanf(
" %d " , & g[i][j]);
}
}
CreatGraph();
Ford_Fulkerson();
}
return 0 ;
}

 

转载于:https://www.cnblogs.com/ylfdrib/archive/2010/06/28/1767037.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值