http://acm.pku.edu.cn/JudgeOnline/problem?id=3436
题目大意:每个电脑需要P个组成部分,现有N的机器,每个机器都可以对电脑进行加工,不过加工的前提是某些部分已经存在。且每个机器的加工都有一个performance,要求能得到的最大performance.
算法分析:最大流,没用到一点优化,依然不会sap,dinic,直接bfs()搞定的,不过这次的bfs(),我没有用STL,而是手动模拟了一下,又学习到一个好的模拟队列方法,不用更新队列,直接更新长度,将值都放在同一个数组里存着,按顺序出队就行了。继续努力!
总结一点:做图论题,关键就在建图,找到建图方法,只要有模板,并且熟悉,就能很快解决了。做题时,不要过早放弃,多想想,别太早就去翻标程,这样不容易达到锻炼思维,锻炼自己分析问题,快速建图的目的。


#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 ;
}
#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 ;
}