HDU4280 Island Transport【最大流】【SAP】

题目链接:

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;
}
时间: 2024-11-05 16:54:03

HDU4280 Island Transport【最大流】【SAP】的相关文章

hdu4280 Island Transport(最大流Dinic数组模拟邻接连边)

Island Transport Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 10716    Accepted Submission(s): 3430 Problem Description In the vast waters far far away, there are many islands. People are l

HDU 4280 Island Transport(网络流,SAP)

解题思路: 建模很简单,不过以前一直用dinic,而这个题目数据偏大,用dinic超时了,据说没有可以卡住SAP的网络流,于是搞到了一套SAP的模版,过了,保存一下模版. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <cstdlib> #include <vector> #include <queue>

HDU4280:Island Transport(最大流)

Island Transport Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 13187    Accepted Submission(s): 4156 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4280 Description: In the vast waters far f

Hdu 4280 Island Transport(最大流)

Island Transport Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 6217    Accepted Submission(s): 1965 Problem Description In the vast waters far far away, there are many islands. People are l

HDU 4280 Island Transport 网络流裸题

非递归版好像被卡掉了,其他2个板子都能过. #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<vector> using namespace std; #define ll int const int MAXN = 100100;//点数的最大值 const int MAXM = 400010;//边数的最大值 const in

Island Transport

Island Transport Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 6354    Accepted Submission(s): 1995 Problem Description In the vast waters far far away, there are many islands. People are li

HDU 4280 Island Transport(网络流模板)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4280 Problem Description In the vast waters far far away, there are many islands. People are living on the islands, and all the transport among the islands relies

HDU3605Escape(最大流SAP+状态压缩优化点的个数)

Escape Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6239    Accepted Submission(s): 1474 Problem Description 2012 If this is the end of the world how to do? I do not know how. But now scient

HDU 3277 Marriage Match III(拆点+二分+最大流SAP)

这个题目是说,有n个女的和男的找伴侣.然后女的具有主动选择权,每个女的可以选自己喜欢的男的,也可以挑选k个不喜欢的男的,做法就是:把女的拆点,u1->u2建立一条容量为k的边.如果遇见喜欢的男生i->j+2*n建一条容量为1的边,否则i+n->j+2*n建一条容量为1的边.最后将源点和女生相连容量为mid,汇点与男生相连容量为mid.枚举mid,看是否会产生满流. 可能姿势不够优美dinic超时了啊,换成SAP快了很多啊... Marriage Match III Time Limit: