poj 1149 pigs

本文探讨了一道网络流问题的解决策略及其优化过程,包括建立二分图、使用边集数组进行操作以及实现SAP算法以提高效率。通过案例分析,展示了不同时间复杂度的实现方式及背后的原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一道自己yy的网络流 其实是很水的题目

被猪坑了好长时间

建立二分图 分别是猪圈和买猪的人..

然后用边集数组记录能划到一个范围的猪圈

每次来取猪的时候 先讲一个范围的猪圈与买主连一条边

然后更新边集数组 就ac了 网络卡了 我就连交了3次

时间有16ms 也有0ms的 诧异..

代码:

#include <cstdio>

#include <cstring>
#include <iostream>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 2000;

const int inf = 0x7fffffff;

const int s = 0;

int p[MAXN];
int e[MAXN][MAXN];

int find ( int x )
{
    while ( p[x] != x )
        x = p[x] ;
    return x;
}

struct edge{
       int v,next,w;
}edge[1000000];

int head[2*MAXN],cnt;//for sap

void debug ( )
{
    cout << "here" << endl;
}

void addedge(int u, int v, int w)
{
     edge[cnt].v = v;
     edge[cnt].w = w;
     edge[cnt].next = head[u];
     head[u] = cnt++;
     edge[cnt].v = u;
     edge[cnt].w = 0;
     edge[cnt].next = head[v];
     head[v] = cnt++;
}

int sap(int t)
{
    //debug ();
    int pre[2*MAXN],cur[2*MAXN],dis[2*MAXN],gap[2*MAXN]; //gap标记断层 这里可能会挂掉
    int flow = 0 , aug = inf ,u;
    bool flag;
    for (int i = 0 ; i <= t ; ++i)
    {
        cur[i] = head[i];
        gap[i] = dis[i]=0;
    }
    //debug ();
    gap[s] = t+1;
    u = pre[s] = s;
    while (dis[s] <= t)
    {
        //debug () ;
          flag = 0 ;
          for (int &j = cur[u] ; ~j ; j = edge[j].next)
          {
              int v = edge[j].v;
              //debug ();
              //cout << u << " **** " << v << endl;
              if (edge[j].w > 0 && dis[u] == dis[v]+1)
              {
                   flag = 1;
                   if( edge[j].w < aug )aug = edge[j].w;
                   pre[v] = u;
                   u = v;
                   if (u == t)
                   {
                       flow += aug;
                       while ( u != s )
                       {
                             u = pre[u];
                             edge[cur[u]].w -= aug;
                             edge[cur[u]^1].w += aug;
                       }
                       aug = inf;
                   }
                   break;
              }
          }
          if ( flag )continue ;
          int mindis = t+1;
          for (int j = head[u]; ~j ; j = edge[j].next)
          {
              int v = edge[j].v;
              if ( edge[j].w > 0 && dis[v] < mindis)
              {
                 mindis = dis[v];
                 cur[u] = j;
              }
          }
          if( --gap[dis[u]] == 0)break;
          gap[ dis[u] = mindis+1 ]++;
          u = pre[u];
    }
    return flow;
}

void init ()
{
     memset (head , -1 , sizeof(head));
     cnt=0;
     for ( int i = 0 ; i < MAXN ; i ++ )
        e[i][0] = 0;
}

void insert ( int a, int b )
{
    int flag = 0;
    for ( int i = 1 ; i <= e[a][0] ; i ++ )
    {
        if ( e[a][i] == b )
            flag = 1;
    }
    if ( flag == 0 )
    {
        e[a][0] ++;
        e[a][e[a][0]] = b;
    }

}
int main()
{
    int m , n;
    while ( scanf("%d%d" , &m , &n )!= EOF )
    {
        init();
        int num[MAXN];
        int pig[MAXN];
        //memset ( p_time , -1 , sizeof ( p_time ));
        //memset ( used , 0 , sizeof ( used ));
        for ( int i = 1 ; i <= m ; i ++ )
            scanf("%d" , &num[i] );
        for ( int i = 1 ; i <= m ; i ++ )
            addedge ( 0 , i , num[i] );
//        for ( int i = 0 ; i <= m+n ; i ++ )
//            for ( int j = head[i] ; j != -1 ; j = edge[j].next )
//                cout << i << "***** " << edge[j].v << endl,getchar();
        for ( int i = 0 ; i < n ; i ++ )
        {
            int a , b;
            scanf("%d" , &a );
            for ( int j = 0 ; j < a ; j ++ )
            {
                scanf("%d", &pig[j] );
                for ( int k = 1 ; k <= e[pig[j]][0] ; k ++ )
                    addedge ( e[pig[j]][k] , m+1+i , inf );
                addedge ( pig[j] , m+1+i, inf );
            }
            for ( int j = 0 ; j < a ; j ++ )
                for ( int  k = 0 ; k < a ; k ++ )
                        insert ( pig[j] , pig[k] );
            scanf("%d" , &b );
            addedge ( m+1+i , m+1+n , b );
        }
        printf("%d\n" , sap ( n+m+1 ));
    }
    return 0;
}

网上其他的方法:

开始时用猪圈数当节点,发现节点数很多,而且顾客的先后顺序不容易控制,然后发现,顾客的数目只有100个,那么以顾客为节点就容易多了,如果某个顾客是第一次拿某个猪圈的钥匙,则在源与顾客间连线,大小为猪的初始数目,否则就把前一个拥有钥匙的人和这个人连一条线,大小为无穷大,每个顾客都与汇相连,然后求最大流即可


其实这个方法就是把上面的节点压缩了 这样就能快很多..

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值