zoukankan      html  css  js  c++  java
  • ccf 201812-5

    题解:最小费用可行流

    有bug,处理一部分数据的时候会死循环,先码着

    #include <stdio.h>
    #include <string.h>
    #include <queue>
    #define INF 0x3f3f3f3f
    #define MAX 205
    #define MAX_EDG 505
    
    using namespace std;
    
    typedef struct Node{
        int to;        //边的终点 
        int cap;    //当前最大容量 
        int cost;    //单位流量的费用 
        int next;    //相同起点的下一条边在map中的编号(位置) 
    }Node;
    
    Node map[MAX_EDG*2];    //存边:正向边 + 反向边 
    int vis[MAX];
    int dis[MAX];        //s到第i个顶点的最小代价 
    int pre[MAX];
    int flow[MAX];        //s到第i个顶点可更新的最大流量 
    int head[MAX];        //第i个顶点的第一条边在map中的位置 
    int count;        //计数,第几个顶点 
    int n,m,s,t;        
    int max_flow, min_cost;        //最大流 最小费用 
    int du[MAX];        //记录顶点的出入度 
    queue<int> q;
    
    
    void add_edge(int from, int to, int cap, int cost){        //from起点    to终点    cap当前容量     cost单位费用 
        map[count].to=to;
        map[count].cap=cap;
        map[count].cost=cost;
        map[count].next=head[from];
        head[from]=count++;            //更新count        
    }
    
    bool spfa(int s, int t){
        memset(dis,INF,sizeof(dis));
        memset(vis,0,sizeof(vis));
        q.push(s);
        vis[s]=1;
        dis[s]=0;
        flow[s]=INF;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=0;        //为什么
            for(int i=head[u] ;i!=-1; i=map[i].next){        //i是边在map中的编号 
                if(!map[i].cap)        continue;        //当前边没有可增加的容量了,就跳过
                int v=map[i].to;
                int w=map[i].cost;
                if(dis[v] > dis[u] + w)
                {
                    dis[v]=dis[u]+w;
                    flow[v]=min(flow[u],map[i].cap);    //取到边的起点u可更新的流量和这条边的剩余容量的最小值
                    pre[v]=i;        //
                    if(!vis[v]){
                        vis[v]=1;
                        q.push(v);
                    } 
                } 
            } 
        }
        return dis[t]!=INF;        //
    }
    
    
    int MFMC(int s, int t){        //
        while(spfa(s,t)){        //还存在增广路 
            int x= t;
            max_flow+=flow[t];
            min_cost+=flow[t]*dis[t];
            while(x!=s){                //遍历增广路        //bug:这里会死循环
                   printf("x!=s
    ");
                int i=pre[x];
                map[i].cap-=flow[t];        //正向弧减 
                map[i^1].cap+=flow[t];        //反向弧加 
                x=map[i^1].to;
            }
        }
    }
    
    int main(){                //最小费用可行流 
        int T,u,v,e;
        char type;
        int num,sum;
        while(scanf("%d %d %d",&T,&s,&e)!=EOF){        //此处的s没有用 
            for(int i=0;i<T;i++){
                scanf("%d %d",&n,&m);
                 memset(head,-1,sizeof(head));
                memset(du,0,sizeof(du));
                s=0;    t=n+1;
                count=0;
                num=0;    sum=0;
                max_flow=min_cost=0;
                for(int j=0;j<m;j++){
                    scanf("%d %d %c",&u,&v,&type);
                    if(type=='A'){            //A:流量上界是INF,下界是1,容量是INF-1=INF 
                        add_edge(u,v,INF,e);
                        add_edge(v,u,0,-e);
                        du[u]--;            //u流出 
                        du[v]++;            //v流入 
                        num+=e;
                    }
                    else if(type=='B'){            //B:流量上界为1,下界也是1,所以容量为1-1=0 
                        du[u]--;            //容量0,不建边 
                        du[v]++;
                        num+=e; 
                    }
                    else if(type=='C'){            //C:流量上界为INF,下界为0,所以容量=INF 
                        add_edge(u,v,INF,e);
                        add_edge(v,u,0,-e);
                    }
                    else{                        //D:流量上界是1,下界是0,所以容量是1 
                        add_edge(u,v,1,e);
                        add_edge(v,u,0,-e);
                    }
                }
                for(int j=1;j<=n;j++){
                    if(du[j]>0){        //流入大于流出 
                        sum+=du[j];
                        add_edge(s,j,du[j],0);        //和s点相连 
                    }
                    else if(du[j]<0){        //流出大于流入 
                        add_edge(j,t,-du[j],0);        //和t点相连 
                    }            
                }
                printf("MACF 前
    ");    
                MFMC(s,t);
                printf("MfMC 后
    ");
                if(max_flow!=sum)    printf("-1
    ");
                else    printf("%d
    ",min_cost+num);    
            }        
        }
        return 0;
    }
  • 相关阅读:
    hnoi2013
    图片屏幕LibGdxGearJoint齿轮关节
    数据属性WEKA学习总结
    函数调用[置顶] C/C++在main函数之前和之后会做些什么
    系统控制2013北京照明展后记
    终端安装解决svn "cannot set LC_CTYPE locale"的问题
    系统服务器Fedora和Red Hat Enterprise Linux实用指南(第6版)(上、下册)( 入行必读的Linux圣经)
    文件数据库Android面试题(三)
    UML中的活动图
    UML模型
  • 原文地址:https://www.cnblogs.com/shiliuxinya/p/12203311.html
Copyright © 2011-2022 走看看