• poj 2455二分+dinic求最大流


    直接搬人家的博客吧,感觉比我自己写的好多了!

    poj 2455 Secret Milking Machine 二分 + dinic求最大流
    
    //poj 2455 Secret Milking Machine
    //二分 + 最大流
    
    //题意:
    //输入第一行3个数为结点数,边数,路径数
    //接下来为每条边的信息
    //要求找出对应路径数中每条边都尽量小,输出这些路径中的边最长边为多少
    //每条边只能用一次
    
    //思路:
    //对路径中的最长边进行二分,之后用最大流在符合边长限制的边中找看看有几条从
    //起点 1 到终点 n的路,若大于限制的路径数就向左二分,反之向右二分
    
    //注意:
    //dinic:广搜时记得要有容量的且端点没分过层的才可以进行分层;
    //深搜时求流向下一结点的流量为流到该结点的流量flow减去已经从该结点
    //流出去的流量tmp,并和现在遍历到得边的容量相比,取小的往下一节点流,
    //m = min(edge[i].cap, flow - tmp);最后若从目前结点没有流量流出,
    //则把它的层标记为-1,即下次不能流到这一结点了
    
    //具体看代码注释
    
    #define infile freopen("in.txt", "r", stdin);
    #include <stdio.h>
    #include <string.h>
    #include <queue>
    using namespace std;
    
    const int INF = 1<<30;
    const int N = 205;
    
    struct LINE
    {
        int st, ed, dis;
    }line[N*N];
    
    struct EDGE
    {
        int st, ed, dis, cap, next;
    }edge[2*N*N];
    
    int eid;
    int head[N], level[N];
    
    void add_edge(int st, int ed, int dis)
    {
        edge[eid].st = st;
        edge[eid].ed = ed;
        edge[eid].dis = dis;
        edge[eid].cap = 1;      //每条边只能用一次,所以容量为 1
        edge[eid].next = head[st];
        head[st] = eid++;
    
        edge[eid].st = ed;      //双向边,建反向边
        edge[eid].ed = st;
        edge[eid].dis = dis;
        edge[eid].cap = 1;
        edge[eid].next = head[ed];
        head[ed] = eid++;
    }
    
    bool bfs(int source, int sink)
    {
        memset(level, 0, sizeof(level));
        queue<int>que;
        que.push(1);
        level[1] = 1;
        while(!que.empty())
        {
            int now = que.front();
            que.pop();
            for(int i = head[now]; i != -1; i = edge[i].next)
            {
                int ed = edge[i].ed;
                if(edge[i].cap > 0 && level[ed] == 0)   //边要有容量且结点还没被分层才对它分层
                {
                    level[ed] = level[now] + 1;
                    que.push(ed);
                }
            }
        }
        return level[sink];
    }
    
    int dfs(int now, int sink, int flow)
    {
        if(now == sink)
            return flow;
        int tmp = 0, f;
        for(int i = head[now]; i != -1; i = edge[i].next)
        {
            int ed = edge[i].ed;
            int m = min(edge[i].cap, flow - tmp);   //流到下一结点的流量
    
            //流到now结点的流量为flow,从now流出去的流量为tmp
            //所以个人觉得这里的 tmp < flow 可以不用,因为上面的最小值让
            if(level[now] + 1 == level[ed] && edge[i].cap > 0 &&
               tmp < flow && (f = dfs(ed, sink, m)))
            {
                edge[i].cap -= f;
                edge[i^1].cap += f;
                tmp += f;
            }
        }
        if(tmp == 0)
            level[now] = -1;
        return tmp;
    }
    
    int dinic(int source, int sink)
    {
        int flow = 0;
        while(bfs(source, sink))    //广搜进行分层
            flow += dfs(source, sink, INF); //深搜找最大流
        return flow;
    }
    
    void binarySearch(int n_node, int n_edge, int limit, int high)
    {
        int low = 1;
        while(low < high)   //对路径的最长边二分
        {
            eid = 0;
            memset(head, -1, sizeof(head));
            int mid = low + (high-low)/2;
            for(int i = 0; i < n_edge; ++i)
                if(line[i].dis <= mid)      //把符合要求的边都加入邻接表中
                    add_edge(line[i].st, line[i].ed, line[i].dis);
            int flow = dinic(1, n_node);
            if(flow >= limit)
                high = mid;
            else
                low = mid + 1;
        }
        printf("%d\n", low);
    }
    
    int main()
    {
        //infile
        int n_node, n_edge, limit;
        while(scanf("%d%d%d", &n_node, &n_edge, &limit) != EOF)
        {
            int m = 0;
            for(int i = 0; i < n_edge; ++i)
            {
                scanf("%d%d%d", &line[i].st, &line[i].ed, &line[i].dis);
                m = m < line[i].dis ? line[i].dis : m;  //记录最长边
            }
            binarySearch(n_node, n_edge, limit, m);
        }
        return 0;
    }
  • 相关阅读:
    【Git】Git 学习笔记(一)
    【工程 Shell】Shell 学习(一)
    Vue 使用 Antd 简单实现左侧菜单栏和面包屑功能
    GoF的23种设计模式的功能
    ASP 对数据库的操作
    注册表修改USB状态(开与关)
    EXE文件关联修复
    CentOS8安装Docker
    GoogleEarth无法连接服务器解决方法
    【转】Qt 实现的拷贝 文件/文件夹 的函数
  • 原文地址:https://www.cnblogs.com/chaosheng/p/2700578.html
Copyright © 2020-2023  润新知