ccf 201812-5

Posted shiliuxinya

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于ccf 201812-5的主要内容,如果未能解决你的问题,请参考以下文章

CCF(管道清洁):最小费用最大流

最小费用可行流

多线程中共享变量——CCF总决赛试题

CCF推荐系统项目代码解读!

CCF CSP 202109赛题练习

ccf 201903-4 消息传递接口 100