码迷,mamicode.com
首页 > 其他好文 > 详细

HDU4280 Island Transport【最大流】【SAP】

时间:2015-04-09 19:58:47      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4280


题目大意:

有N个岛屿,M条双向道路。每条路每小时最多能通过Ci个人。给你N个岛屿的坐标。问:一个小时内,

最多能将多少游客从最西边的岛送至最东边的岛屿上。


思路:

网络流求最大流的裸题。先通过坐标找到最西边的岛屿和最东边的岛屿,记录并标记为源点和汇点。然后

用链式前向星来存储图,将M条双向边加入到图中。然后用SAP算法来做,据说还没有卡SAP的网络流。

算法用了GAP优化、当前弧优化,具体参考代码。


AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN = 100010;        //最大点个数
const int MAXM = MAXN*4;
const int INF = 0xffffff0;

struct EdgeNode
{
    int to;
    int next;
    int w;
}Edges[MAXM];
int Head[MAXN],id;                  //链式前向星

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
    Edges[id].to = u;
    Edges[id].w = 0;
    Edges[id].next = Head[v];
    Head[v] = id++;
}
int Numh[MAXN],h[MAXN],curedges[MAXN],pre[MAXN];
//Numh:用于GAP优化的统计高度数量数组;
//h:距离标号数组;
//curedges:当前弧数组
//pre:前驱数组

void BFS(int end,int N) //BFS求出每个点的距离标号值
{
    memset(Numh,0,sizeof(Numh));
    for(int i = 1; i <= N; ++i)
        Numh[h[i]=N]++;
    h[end] = 0;
    Numh[N]--;
    Numh[0]++;
    queue<int> Q;
    Q.push(end);

    while(!Q.empty())
    {
        int v = Q.front();
        Q.pop();
        int i = Head[v];
        while(i != -1)
        {
            int u = Edges[i].to;

            if(h[u] < N)
            {
                i = Edges[i].next;
                continue;
            }

            h[u] = h[v] + 1;
            Numh[N]--;
            Numh[h[u]]++;
            Q.push(u);
            i = Edges[i].next;
        }
    }
}

int SAPMaxFlow(int start,int end,int N)
{
    int CurFlow,FlowAns = 0,temp,neck;  //FlowAns:最大流,初始化为0
    memset(h,0,sizeof(h));
    memset(pre,-1,sizeof(pre));
    for(int i = 1; i <= N; ++i)
        curedges[i] = Head[i];          //初始化当前弧为第一条邻接边
    //Numh[0] = N;
    BFS(end,N);
    int u = start;
    while(h[start] < N)          //当h[start] >= N时,网络中肯定出现了GAP
    {
        if(u == end)
        {
            CurFlow = INF;
            for(int i = start; i != end; i = Edges[curedges[i]].to)
            {
                if(CurFlow > Edges[curedges[i]].w)
                {
                    neck = i;
                    CurFlow = Edges[curedges[i]].w;
                }
            }   //增广成功,寻找"瓶颈"边
            for(int i = start; i != end; i = Edges[curedges[i]].to)
            {
                temp = curedges[i];
                Edges[temp].w -= CurFlow;
                Edges[temp^1].w += CurFlow;
            }   //修改路径上的边容量
            FlowAns += CurFlow;
            u = neck;   //下一次增广从瓶颈边开始
        }
        int i;
        for(i = curedges[u]; i != -1; i = Edges[i].next)
            if(Edges[i].w && h[u] == h[Edges[i].to]+1)
                break;  //寻找可行弧
        if(i != -1)     //GAP优化
        {
            curedges[u] = i;
            pre[Edges[i].to] = u;
            u = Edges[i].to;
        }
        else
        {
            if(0 == --Numh[h[u]])
                break;
            curedges[u] = Head[u];
            for(temp = N,i = Head[u]; i != -1; i = Edges[i].next)
                if(Edges[i].w)
                    temp = min(temp,h[Edges[i].to]);
            h[u] = temp + 1;
            ++Numh[h[u]];
            if(u != start)      //重新标号并从当前点前驱重新增广
                u = pre[u];
        }
    }
    return FlowAns;
}

int main()
{
    int T,N,M,u,v,w;
    int start,end;
    scanf("%d",&T);
    while(T--)
    {
        int Max = -INF,Min = INF;
        scanf("%d%d",&N,&M);
        for(int i = 1; i <= N; ++i)     //找到最西边和最东边的岛,记录源点和汇点
        {
            scanf("%d%d",&u,&v);
            if(u <= Min)
            {
                Min = u;
                start = i;
            }
            if(u >= Max)
            {
                Max = u;
                end = i;
            }
        }
        memset(Head,-1,sizeof(Head));
        id = 0;
        for(int i = 0; i < M; ++i)      //添加边
        {
            scanf("%d%d%d",&u,&v,&w);
            AddEdges(u,v,w);
            AddEdges(v,u,w);
        }
        printf("%d\n",SAPMaxFlow(start,end,N)); 
    }

    return 0;
}


HDU4280 Island Transport【最大流】【SAP】

标签:

原文地址:http://blog.csdn.net/lianai911/article/details/44962653

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!