猜测 [最小费用最大流]

猜 测 猜测



正 解 部 分 \color{red}{正解部分}

将每个相同的 x x x 坐标 与 源点费用 0 0 0, 容量 n u m x i num_{x_i} numxi 的边,
每个相同的 y y y 坐标 与 汇点费用 0 0 0, 容量 n u m y i num_{y_i} numyi 的边,
x i x_i xi y i y_i yi费用 1 1 1, 容量 1 1 1 的边, x i x_i xi y j y_j yj费用 0 0 0, 容量为 1 1 1 的边 .

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


实 现 部 分 \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\n", Ans);
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值