zoukankan      html  css  js  c++  java
  • poj2175费用流消圈算法

    题意:
         有n个建筑,每个建筑有ai个人,有m个避难所,每个避难所的容量是bi,ai到bi的费用是|x1-x2|+|y1-y2|+1,然后给你一个n*m的矩阵,表示当前方案,问当前避难方案是否是最优的,如果不是,输出一个比这个好的就行。


    思路:
        大体看一下题目,很容易想到费用流直接去弄,建图也比较简单,但是费用流超时,仔细看上面的最后一句,是找到一个比当前的好就行,不用最好,这样我们可以考虑费用流的消圈,我也是今天第一次听到这个东西,研究了将近两个小时,大体明白了,明白后再反过来想想确实很简单,学东西就这样,很正常,下面说下消圈算法,消圈可以用来判断费用流的当前状态是否是最优的,大体是这样,我们先建立残余网络,就是根据题目给的信息建出残余图,如果是初学建议不要向网上很多人那样直接建立部分有用边(初学很容易不懂),我们可以这样,把所有的残余网络都补上,我写下本题的建边过程方便理解(正反边分开建立):


    ss -> i  流量0 费用0  
             //因为跑完之后前面肯定是流量都用没了
    i -> ss 流量c ,费用0 
             //c是这个建筑有多少人,满流的正向0,反向满c
    i -> j + n 流量INF-c 费用 w
             //w是i,j的距离+1,c是建筑里人数,本来是INF,跑完后是INF-c
    j+n -> i  流量c ,费用w
             //如上
    j+n -> tt 流量q,费用0,
             //q是建筑的容量剩余,就是所有的-当前用了的,当前用的综合自己算出来
    tt -> j+n 流量p,费用0
             //p是当前这个避难所一共用了多少容量


    建图之后从重点开始跑最短路,如果没有发现负权值回路那么就是最优的,否则我们就随便找到一个负权值回路,然后把i->j的边的流量++,j->i的边的流量--,至于为什么这样我们可以这样想,首先建议现在纸上大体画一下,自己随便找一个负权值回路,然后看看特点,从终点开始跑,发现负权值回路说明正值<负值(花费),那么我们把负值的流量-1给正值得流量+1,是不是即达到了流量平衡有减少了花费呢?还有找负权值回路的时候和费用流是一样的,费用更小(最短路)同时有流量才能跑,如果还不懂就不停的画,画着画着就懂了,还有画的过程中记得去想费用流的反向费用是负的,最大流的反向流量就是正向流量的减少量,还有一点就是注意一下,找负环的时候,如果用的是Spfa的话,最后一个有可能不是环上的,这样我们就得先找到一个肯定是环上的点,这个好办,直接mark,从后往前一直找到mark过的就跳出来,当前这个肯定是环上的(不明白的话可以在纸上画几个6感觉下),具体看代码。


    #include<queue>
    #include<stdio.h>
    #include<string.h>
    
    #define N_node 205
    #define N_edge 30000
    #define INF 100000000
    
    using namespace std;
    
    typedef struct
    {
        int from ,to ,cost ,flow ,next;
    }STAR;
    
    typedef struct
    {
        int a ,b ,c;
    }NODE;
    
    STAR E[N_edge];
    int list[N_node] ,tot;
    int C[N_node];//入队次数
    int mer[N_node];//记录路径
    int s_x[N_node] ,mark[N_node];
    int now[N_node][N_node];
    NODE A[N_node] ,B[N_node];
    
    void add(int a ,int b ,int c ,int d)
    {
        E[++tot].from = a;
        E[tot].to = b;
        E[tot].cost = c;
        E[tot].flow = d;
        E[tot].next = list[a];
        list[a] = tot;
    }
    
    int abss(int x)
    {
        return x > 0 ? x : -x;
    }
    
    bool Spfa(int s ,int n)
    {
        for(int i = 0 ;i <= n ;i ++)
        s_x[i] = INF;
        memset(mark ,0 ,sizeof(mark));
        memset(C ,0 ,sizeof(C));
        queue<int>q; q.push(s);
        mark[s] = C[s] = 1 ,s_x[s] = 0;
        int xin ,tou;
        memset(mer ,255 ,sizeof(mer));
        while(!q.empty())
        {
            tou = q.front();
            q.pop();
            mark[tou] = 0;
            for(int k = list[tou] ;k ;k = E[k].next)
            {
                xin = E[k].to;
                if(s_x[xin] > s_x[tou] + E[k].cost && E[k].flow)
                {
                    s_x[xin] = s_x[tou] + E[k].cost;
                    mer[xin] = k;
                    if(!mark[xin])
                    {
                        mark[xin] = 1;
                        q.push(xin);
                        if(++C[xin] > n) return xin;
                    }
                }
            }
        }
        return 0;
    }
    
    int main ()
    {
        int n ,m ,i ,j;
        int st[N_node];
        while(~scanf("%d %d" ,&n ,&m))
        {
            for(i = 1 ;i <= n ;i++)
            scanf("%d %d %d" ,&A[i].a ,&A[i].b ,&A[i].c);
            for(i = 1 ;i <= m ;i ++)
            scanf("%d %d %d" ,&B[i].a ,&B[i].b ,&B[i].c);
            memset(st ,0 ,sizeof(st));
            for(i = 1 ;i <= n ;i ++)
            for(j = 1 ;j <= m ;j ++)
            {
                scanf("%d" ,&now[i][j]);
                st[j] += now[i][j];
            }
            memset(list ,0 ,sizeof(list));
            tot = 1;
            int ss = 0 ,tt = n + m + 1;
            for(i = 1 ;i <= n ;i ++)
            add(ss ,i ,0 ,0),add(i ,ss ,0 ,A[i].c);
            for(i = 1 ;i <= m ;i ++)
            add(i + n ,tt ,0 ,B[i].c - st[i]) ,add(tt ,i + n ,0 ,st[i]);
            for(i = 1 ;i <= n ;i ++)
            for(j = 1 ;j <= m ;j ++)
            {
                add(i ,j + n ,abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1 ,INF - now[i][j]);
                add(j + n ,i ,-(abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1) ,now[i][j]);
            }
            int x = Spfa(tt ,tt);
            if(!x)
            {
                printf("OPTIMAL
    ");
                continue;
            }
            printf("SUBOPTIMAL
    ");
            memset(mark ,0 ,sizeof(mark));
            i = mer[x];
            while(1)//找到一个肯定在环上的点
            {
                x = E[i].to;
                if(mark[x]) break;
                mark[x] = 1;
                i = mer[E[i].from];
            }
            memset(mark ,0 ,sizeof(mark));
            for(i = mer[x] ;i + 1 ;i = mer[E[i].from])
            {
                int a = E[i].from ,b = E[i].to;
                if(a >= 1 && a <= n && b >= n + 1 && b <= n + m)
                now[a][b-n] ++;
                if(a >= n + 1 && a <= n + m && b >= 1 && b <= n)
                now[b][a-n] --;
                if(mark[a] && mark[b]) break;
                mark[a] = mark[b] = 1;
            }
            for(i = 1 ;i <= n ;i ++)
            for(j = 1 ;j <= m ;j ++)
            if(j == m) printf("%d
    " ,now[i][j]);
            else printf("%d " ,now[i][j]);
        }
        return 0;
    
    }
    
    
    


  • 相关阅读:
    Elementary Methods in Number Theory Exercise 1.3.13
    Elementary Methods in Number Theory Exercise 1.3.17, 1.3.18, 1.3.19, 1.3.20, 1.3.21
    数论概论(Joseph H.Silverman) 习题 5.3,Elementary methods in number theory exercise 1.3.23
    Elementary Methods in Number Theory Exercise 1.2.31
    数论概论(Joseph H.Silverman) 习题 5.3,Elementary methods in number theory exercise 1.3.23
    Elementary Methods in Number Theory Exercise 1.3.13
    Elementary Methods in Number Theory Exercise 1.3.17, 1.3.18, 1.3.19, 1.3.20, 1.3.21
    Elementary Methods in Number Theory Exercise 1.2.31
    Elementary Methods in Number Theory Exercise 1.2.26 The Heisenberg group
    4__面向对象的PHP之作用域
  • 原文地址:https://www.cnblogs.com/csnd/p/12062392.html
Copyright © 2011-2022 走看看