UVa10779 Collectors' Problem( 网络流,建图)

这是一道建图的题,只要能想清楚怎么建图,就没有问题

建图:Bob和所有粘贴相连,边的容量是他所拥有粘贴的个数;

            其他人和他们所拥有的粘贴相连,边容量为手中物品个数减1,因为他们要保留一个

            其他人没有的粘贴,从粘贴连到这个人,容量为1,他只能接受一个这种粘贴

            每种粘贴和汇点相连,容量为1

代码如下:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

const int inf = 99999999;
const int Maxn = 40;
int S, E, T, n, m;
int map[Maxn][Maxn], flow[Maxn][Maxn], a[Maxn], p[Maxn];

void buildMap() {
    int ki, t;
    for ( int i = 1; i <= n; ++i ) {
        scanf("%d", &ki);
        for ( int j = 0; j < ki; ++j ) {  
            scanf("%d", &t);
            t += n; 
            map[i][t]++;
        }
        if ( i > 1 ) for ( int j = n + 1; j <= n + m; ++j ) 
            if ( map[i][j] ) map[i][j]--;
            else if ( map[i][j] == 0 ) map[j][i]++;
    }
    for ( int i = n + 1; i <= n + m; ++i ) map[i][E]++; //将表示物品的点和汇点相连,容量为1
}
int maxFlow() {
    queue < int > q; int f = 0;
    memset( flow, 0, sizeof(flow) );
    while(1) {
        memset( a, 0, sizeof(a) );
        a[S] = inf;
        q.push( S );
        while( !q.empty() ) {
            int u = q.front(); q.pop();
            for( int v = 1; v <= m + n + 1; ++v ) {
                if ( !a[v] && map[u][v] > flow[u][v] ) {
                    p[v] = u; q.push(v);
                    a[v] = min(a[u], map[u][v] - flow[u][v]);
                }
            }
        }
        if ( a[E] == 0 ) break;
        for ( int u = E; u != S; u = p[u] ) {
            flow[p[u]][u] += a[E];
            flow[u][p[u]] -= a[E];
        }
        f += a[E];
    }
    return f;
}

int main()
{
    int icase = 1;
    while ( scanf("%d", &T) != EOF ) {
        while ( T-- ) {
            scanf("%d%d", &n, &m);
            memset( map, 0, sizeof(map) );
            S = 1, E = m + n + 1;
            buildMap();
            printf("Case #%d: %d\n", icase++, maxFlow());
        }
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值