zoukankan      html  css  js  c++  java
  • 猜测 [最小费用最大流]

    猜测



    color{red}{正解部分}

    将每个相同的 xx 坐标 与 源点费用00, 容量numxinum_{x_i} 的边,
    每个相同的 yy 坐标 与 汇点费用00, 容量numyinum_{y_i} 的边,
    xix_iyiy_i费用11, 容量11 的边, xix_iyjy_j费用00, 容量为 11 的边 .

    然后 答案就是 最小费用最大流 .


    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define pb push_back
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 60;
    const int S = 115, T = 116;
    
    int N;
    int Ans;
    int num0;
    int Len_1;
    int Len_2;
    int B1[maxn<<1];
    int B2[maxn<<1];
    int Dis[maxn<<1];
    int Pre[maxn<<1];
    int head[maxn<<1];
    int used[maxn<<1];
    int num_1[maxn<<1];
    int Pre_2[maxn<<1];
    int num_2[maxn<<1];
    int vis[maxn<<1][maxn<<1];
    
    struct Node{ int x, y; } A[maxn<<1];
    
    struct Edge{ int nxt, to, w, flow, cost; } edge[maxn*maxn<<1];
    
    void Add(int from, int to, int w, int flow, int cost){
            edge[++ num0] = (Edge){ head[from], to, w, flow, cost };
            head[from] = num0;
    }
    
    bool Spfa(){
            memset(Dis, 0x3f, sizeof Dis);
            std::queue <int> Q; Q.push(S);
            Dis[S] = 0, Pre[T] = 0; 
            while(!Q.empty()){
                    int ft = Q.front(); Q.pop(); used[ft] = 0;
                    for(reg int i = head[ft]; i; i = edge[i].nxt){
                            int to = edge[i].to;
                            if(edge[i].w-edge[i].flow > 0 && Dis[to] > Dis[ft] + edge[i].cost){ 
                                    Pre[to] = ft; Pre_2[to] = i; Dis[to] = Dis[ft] + edge[i].cost;
                                    if(!used[to]) used[to] = 1, Q.push(to); 
                            }
                    }
            }
            return Pre[T];
    }
    
    int main(){
            N = read(); 
            for(reg int i = 1; i <= N; i ++){
                    A[i].x = read(), A[i].y = read();
                    B1[++ Len_1] = A[i].x, B2[++ Len_2] = A[i].y;
            }
            std::sort(B1+1, B1+Len_1+1); std::sort(B2+1, B2+Len_2+1);
            Len_1 = std::unique(B1+1, B1+Len_1+1) - B1-1, Len_2 = std::unique(B2+1, B2+Len_2+1) - B2-1;
            for(reg int i = 1; i <= N; i ++){
                    A[i].x = std::lower_bound(B1+1, B1+Len_1+1, A[i].x) - B1;
                    A[i].y = std::lower_bound(B2+1, B2+Len_2+1, A[i].y) - B2;
                    num_1[A[i].x] ++, num_2[A[i].y] ++, vis[A[i].x][A[i].y] = 1;
            }
            num0 = 1;
            for(reg int i = 1; i <= Len_1; i ++) Add(S, i, num_1[i], 0, 0), Add(i, S, 0, 0, 0);
            for(reg int i = 1; i <= Len_2; i ++) Add(i+maxn, T, num_2[i], 0, 0), Add(T, i+maxn, 0, 0, 0);
            for(reg int i = 1; i <= Len_1; i ++)
                    for(reg int j = 1; j <= Len_2; j ++) Add(i, j+maxn, 1, 0, vis[i][j]), Add(j+maxn, i, 0, 0, -vis[i][j]);
            int Tmp = N;
            while(Tmp && Spfa()){
                    int max_flow = 0x3f3f3f3f, t = T;
                    while(t != S) max_flow = std::min(max_flow, edge[Pre_2[t]].w-edge[Pre_2[t]].flow), t = Pre[t];
                    max_flow = std::min(max_flow, Tmp), Ans += max_flow * Dis[T], t = T; Tmp -= max_flow;
                    while(t != S) edge[Pre_2[t]].flow += max_flow, edge[Pre_2[t]^1].flow -= max_flow, t = Pre[t];
            }
            printf("%d
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    去除vue-router 链接上的#号
    input 实现调用本地摄像头 实现拍照 和拍视频
    vue-cli 安装sass 和 font-awesome 笔记
    linux下alias命令详解
    linux下source命令的基本功能
    在Linux命令行窗口中,怎么向上翻页?
    Android内存监测工具使用
    Activity的Theme主题风格
    ListView中CheckBox错乱解决
    绘图之Canvas学习
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822461.html
Copyright © 2011-2022 走看看