zoukankan      html  css  js  c++  java
  • hdu 4309 Seikimatsu Occult Tonneru 枚举+最大流

    http://blog.csdn.net/julyana_lin/article/details/8070949

    题意: n个点,每个点有初始的值 ,三种 通道,1、隧道:可以用来躲避,有固定的容量,也可以用来传递。2、普通的道路,可以无限的通过。3、桥(最多有12座):不花费的话能通过一人,修之后可以无限通过。问最少花费最大可以隐藏人数。

    解:

         网络流 + 枚举

    官方题解:

    先不考虑可以修复的桥的性质,则可以将模型简化为n个点的人通过有通过人数上限的有向边,到达一些有人数上限的特殊的边(隧道)。 可以建立最大流模型来求解,增加一个源点S,和一个汇点T。S向每个有人的点,连一条容量为人数的边,图中普通的u->v的有向边,连一条u->v的流量为无穷的边,桥的流量则为1。对于隧道,每个隧道可以虚拟出一个点,如u->v的隧道,可以虚拟一个点x,连接u->x,x->v的流量无穷的边,和x->T的流量为隧道人数上限的边,求解最大流即可得到最大人数。 现在考虑桥的问题,题目中说明了桥最多只有12座,故可以2^12枚举修复哪些桥,不修复的桥没有花费,连接的边流量为1,要修复的桥则计算花费,边的流量为无穷,这样进行2^12次最大流就可以得到最优解。

    #include <cstdio>
    #include <cstring>
    const int MAXN = 205;
    const int MAXM = 2505;
    const int INF = 1000000000;
    
    struct Edge
    {
        int u, v, next, flow;
    }edge[MAXM], redge[MAXM];
    int edgeNumber, head[MAXN], rhead[MAXN];
    int source = MAXN - 1;
    int destination = MAXN - 2;
    int depth[MAXN];
    
    inline int min(int x, int y)
    {
        return x < y ? x : y;
    }
    
    void addEdgeSub(int u, int v, int flow)
    {
        edge[edgeNumber].u = u;
        edge[edgeNumber].v = v;
        edge[edgeNumber].flow = flow;
        edge[edgeNumber].next = head[u];
        head[u] = edgeNumber ++;
    }
    
    void addEdge(int u, int v, int flow)
    {
        addEdgeSub(u, v, flow);
        addEdgeSub(v, u, 0);
    }
    
    int n, m;
    int bridgePosition[MAXN];
    int bridgeCost[MAXN];
    int bridgeNumber;
    
    bool bfs(int start, int end)
    {
        int front = 0, rear = 0;
        int queue[MAXN];
        memset(depth, -1, sizeof(depth));
        queue[front++] = start;
        depth[start] = 0;
        while(rear < front)
        {
            int k = queue[rear++];
            for(int i=head[k];i!=-1;i=edge[i].next)
            {
                int to = edge[i].v;
                if(-1 == depth[to] && edge[i].flow > 0)
                {
                    depth[to] = depth[k] + 1;
                    queue[front++] = to;
                }
            }
        }
        return -1 != depth[end];
    }
    
    int dinic(int start, int end, int sum)
    {
        if(start == end)
        {
            return sum;
        }
        int temp = sum;
        for(int i=head[start];i!=-1 && sum;i=edge[i].next)
        {
            if(edge[i].flow > 0 && depth[edge[i].v] == depth[start] + 1)
            {
                int a = dinic(edge[i].v, end, min(sum, edge[i].flow));
                edge[i].flow -= a;
                edge[i^1].flow += a;
                sum -= a;
            }
        }
        return temp - sum;
    }
    
    int maxFlow(int start, int end)
    {
        int result = 0;
        while(bfs(start, end))
        {
            result += dinic(start, end, INF);
        }
        return result;
    }
    
    int main()
    {
        int u, v, w, p;
        while(~scanf("%d%d", &n, &m))
        {
            int pointNumber = n + 1;
            edgeNumber = 0;
            bridgeNumber = 0;
            memset(head, -1, sizeof(head));
            for(int i=1;i<=n;++i)
            {
                scanf("%d", &w);
                addEdge(source, i, w);
            }
            for(int i=0;i<m;++i)
            {
                scanf("%d%d%d%d",&u,&v,&w,&p);
                if(p < 0)
                {
                    addEdge(u, pointNumber, INF);
                    addEdge(pointNumber, v, INF);
                    addEdge(pointNumber, destination, w);
                    ++ pointNumber;
                }
                else if(p == 0)
                {
                    addEdge(u, v, INF);
                }
                else
                {
                    bridgePosition[bridgeNumber] = edgeNumber;
                    bridgeCost[bridgeNumber] = w;
                    addEdge(u, v, 1);
                    ++ bridgeNumber;
                }
            }
            memcpy(redge, edge, sizeof(redge));
            memcpy(rhead, head, sizeof(rhead));
            int minCost = INF, maxPeople = - INF;
            for(int i=0;i<(1<<bridgeNumber);++i)
            {
                memcpy(edge, redge, sizeof(edge));
                memcpy(head, rhead, sizeof(head));
                int cost = 0;
                for(int j=0;j<bridgeNumber;++j)
                {
                    if(i&(1 << j))
                    {
                        cost += bridgeCost[j];
                        edge[bridgePosition[j]].flow = INF;
                    }
                }
                int people = maxFlow(source, destination);
                if(people > maxPeople)
                {
                    maxPeople = people;
                    minCost = cost;
                }
                else if(people == maxPeople)
                {
                    minCost = min(minCost, cost);
                }
            }
            if(maxPeople > 0)
            {
                printf("%d %d
    ", maxPeople, minCost);
            }
            else
            {
                printf("Poor Heaven Empire
    ");
            }
        }
        return 0;
    }
  • 相关阅读:
    个人便签
    秒杀系统架构分析与实战
    NPOI大数据分批写入同个Excel
    js获取鼠标坐标位置兼容多个浏览器
    月薪3万的程序员都避开了哪些坑
    怎样理解阻塞非阻塞与同步异步的区别?
    JS中的prototype
    互联网——降级论
    fedora自带OpenJDK,所以如果安装官方的JDK的话要先删除OpenJDK
    cygwin 安装完后不能进入think问题,网上99%都是错误的
  • 原文地址:https://www.cnblogs.com/vermouth/p/3847355.html
Copyright © 2011-2022 走看看