1. 程式人生 > >網路最大流中一般增廣路演算法(標號法)

網路最大流中一般增廣路演算法(標號法)

網路最大流主要有兩大類求解方法:增廣路演算法和預流推進演算法

一般增廣路演算法:主要分為初始流為零流和初始流為非零流的情況!後者在標號的時候注意一條邊是正向連線還是反向連線;若是反向的連線,那麼在調整的時候是減去,若為正向那麼在調整的時候是加上!

 

這裡就poj1149為例寫一道網路流中用標號法求解一般增廣路的方法;

題目的關鍵在於如何構造一個容量網路!

1)將顧客看做除源點和匯點以外的頂點,並且另外設定兩個節點,源點和匯點

2)如果源點和某一個節點的邊有重複,那麼就將權合併

3)源點和每個豬圈的第一位顧客連邊,邊的權值為豬圈中豬的數目

4)若顧客j在顧客i之後開啟某個豬圈,則邊<i,j>

的權是+00,原因就是邁克可以調整各個豬圈中豬的數目來最大化限度的滿足顧客的要求!

5)每個顧客和匯點之間連邊,邊的權就是顧客希望買到的豬的數目

#include <iostream>
#include <cstdio>
#include <cstring>
#define PIG_HOUSE_COUNT 1005
#define CONSUMER 105
#define INF 30000000
using namespace std;
int capacity[CONSUMER][CONSUMER];//每一條邊上的容量
int flow[CONSUMER][CONSUMER];//每一條邊的實際流量
int source,destination;//起點和終點
void init()
{
        int M,N;
        int i,j,temp;//temp,資料臨時儲存
        int PigArray[PIG_HOUSE_COUNT];//每個豬圈的豬的數目
        int KeyNumber;//每一個人擁有的鑰匙數目
        int Pre[PIG_HOUSE_COUNT];//這個豬圈上一個的開啟者
        scanf("%d%d",&M,&N);
        source=0;
        destination=N+1;
        memset(Pre,0,sizeof(Pre));
        memset(capacity,0,sizeof(capacity));
        memset(flow,0,sizeof(flow));
        for(i=0;i<M;i++)
                scanf("%d",&PigArray[i]);
        for(i=1;i<=N;i++)
        {
                scanf("%d",&KeyNumber);
                for(j=0;j<KeyNumber;j++)
                {
                        scanf("%d",&temp);
                        if(Pre[temp]==0)
                           capacity[source][i]=capacity[source][i]+PigArray[temp-1];

                        else
                           capacity[Pre[temp]][i]=INF;
                        Pre[temp]=i;

                }
                scanf("%d",&capacity[i][destination]);
        }
}

void ford()
{
        int i,j;
        int queue[CONSUMER];//模擬佇列
        int flag[CONSUMER];//標號為-1,表示起點;標號為非負數,表示該節點的上一個節點;
        int minadd[CONSUMER];
        int v;//當前的頂點
        int qh,qt,p;

        minadd[0]=INF;
        while(1)//對每一次標號---調整後,再重新標號
        {
                for(i=0;i<CONSUMER;i++)
                        flag[i]=-2;//表示還沒有標號
                flag[0]=-1;
                qh=0;queue[qh]=0;qt=1;
                while(qh<qt&&flag[destination]==-2)//用bfs查詢鄰接點
                {
                        v=queue[qh];qh++;
                        for(i=0;i<=destination;i++)
                        {
                                if(flag[i]==-2&&(p=capacity[v][i]-flow[v][i]))
                                {
                                         minadd[i]=(minadd[v]<p) ? minadd[v]: p ;
                                         flag[i]=v;
                                         queue[qt++]=i;
                                }

                        }
                }

                if(flag[destination]==-2)
                        break;
                for(i=flag[destination],j=destination;i!=-1;j=i,i=flag[i])
                {
                        flow[i][j]+=minadd[destination];//對這次標號後的一條路進行增廣
                        flow[j][i]=-flow[i][j];
                }
        }
        for(i=0,p=0;i<destination;i++)
                p+=flow[i][destination];
        printf("%d\n",p);

}
int main()
{
    init();
    ford();
    return 0;
}