首页 > 其他分享 >CF1913 E Matrix Problem 题解

CF1913 E Matrix Problem 题解

时间:2023-12-19 20:55:52浏览次数:22  
标签:pre Matrix int 题解 cost maxn incf Problem 节点

Link

CF1913 E Matrix Problem

Question

给定一个 \(n\times m\) 的 01 矩阵,你可以把矩阵中的任意一个元素 01 翻转

需要最后的矩阵满足,每行 \(1\) 的个数有 \(A[i]\) 个,每列 \(1\) 的个数有 \(B[i]\) 个

Solution

这貌似是一道非常经典的费用流题目

我们建立 \(n\) 个行节点 ,\(m\) 个列节点,一个源点 \(s\) ,一个汇点 \(t\)

  • 如果 \(a[i][j]==0\) 那么我们把 第 \(i\) 个行节点和第 \(j\) 个列节点之间建一条流量为 \(1\) 费用为 \(1\) 的边

  • 如果 \(a[i][j]==1\) 那么我们把 第 \(i\) 个行节点和第 \(j\) 个列节点之间建一条流量为 \(1\) 费用为 \(-1\) 的边,(因为最后答案需要加上刚开始为 \(1\) 的点的数量,\(-1\) 用于撤销代价)

然后从源点 \(s\) 建一条到每个行节点 \(i\) ,容量为 \(A[i]\) ,费用为 \(0\) 的边

从每个列节点 \(j\) 到汇点 \(t\) ,建一条容量为 \(B[i]\) ,费用为 \(0\) 的边

最后的答案就是最小费用最大流+初始为 \(1\) 的 \(a\) 的数量

Code

#include<iostream>
#include<cstring>
#include<vector>
#include<limits>
using namespace std;
using LL = long long;
const int maxn = 1e4 + 5, maxm = 1e6 + 5;
template<typename cost_t>
struct MinCostMaxFlow{

    const cost_t INF = numeric_limits<cost_t>::max() / 2;
    int h[maxn], e[maxm], ne[maxm], idx;
    cost_t f[maxm], w[maxm], d[maxn], incf[maxn];
    int q[maxn], pre[maxn];
    bool vis[maxn];
    int V, S, T;

    void init(int v, int s, int t){
        for(int i = 0; i <= v; i++) h[i] = -1;
        idx = 0;
        V = v, S = s, T = t;
    }

    void add(int a, int b, cost_t c, cost_t d){
        e[idx] = b, f[idx] = c, w[idx] = d, ne[idx] = h[a], h[a] = idx++;
        e[idx] = a, f[idx] = 0, w[idx] = -d, ne[idx] = h[b], h[b] = idx++;
    }

    bool spfa(){
        int hh = 0, tt = 0;
        for(int i = 0; i <= V; i++){
            d[i] = INF;
            incf[i] = 0;
            vis[i] = 0;
        }
        q[tt++] = S, d[S] = 0, incf[S] = INF;
        while(hh != tt){
            int t = q[hh++];
            if (hh == maxn) hh = 0;
            vis[t] = 0;
            for(int i = h[t]; ~i; i = ne[i]){
                int j = e[i];
                if (f[i] && d[j] > d[t] + w[i]){
                    d[j] = d[t] + w[i];
                    incf[j] = min(incf[t], f[i]);
                    pre[j] = i;
                    if (!vis[j]){
                        vis[j] = 1;
                        q[tt++] = j;
                        if (tt == maxn) tt = 0;
                    }
                }
            }
        }
        return incf[T] > 0;
    }

    pair<cost_t, cost_t> EK(){
        cost_t flow = 0, cost = 0;
        while(spfa()){
            cost_t t = incf[T];
            flow += t, cost += d[T] * t;
            for(int i = T; i != S; i = e[pre[i] ^ 1]){
                f[pre[i]] -= t, f[pre[i] ^ 1] += t;
            }
        }
        return {flow, cost};
    }
};
MinCostMaxFlow<int> flow;

int main(){
    freopen("E.in", "r", stdin);
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);

    int n, m;
    cin >> n >> m;
    vector<vector<int> > c(n + 1, vector<int>(m + 1));
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            cin >> c[i][j];
        }
    }
    int sum1 = 0, sum2 = 0;
    vector<int> a(n + 1), b(m + 1);
    for(int i = 1; i <= n; i++)
        cin >> a[i], sum1 += a[i];
    for(int i = 1; i <= m; i++)
        cin >> b[i], sum2 += b[i];
    if (sum1 != sum2){
        cout << -1 << '\n';
        return 0;
    }
    int s = 0, t = n + m + 1;
    flow.init(n + m + 1, s, t);
    for(int i = 1; i <= n; i++){
        flow.add(s, i, a[i], 0);
    }
    for(int i = 1; i <= m; i++){
        flow.add(i + n, t, b[i], 0);
    }
    int ans = 0;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if (c[i][j] == 0){
                flow.add(i, j + n, 1, 1);
            }
            else{
                ans += 1;
                flow.add(i, j + n, 1, -1);
            }
        }
    }
    auto [f, cost] = flow.EK();
    if (f != sum1) cout << -1 << '\n';
    else cout << ans + cost << '\n';
    return 0;
}

标签:pre,Matrix,int,题解,cost,maxn,incf,Problem,节点
From: https://www.cnblogs.com/martian148/p/17914710.html

相关文章

  • 2023强网杯ez_fmt题解及进阶格式化之劫持子函数
    格式化任意内存读写相信已经是老生常谈了,但是随着题目难度加大,格式化题目给我们的难题逐渐变成了覆写什么,改写什么。这题对我是一道很好的例题,其中对栈及函数调用的理解堪称刷新我的认知。exp先放着,想自己调试理解的可以看看。frompwnimport*context(terminal=['tmux','......
  • CSP2023-12树上搜索题解
    刚考完csp,这道题是大模拟题,题意不难理解。以下是题目链接:http://118.190.20.162/view.page?gpid=T178当时考场上这道题调了好久没调出来,忽略了很多细节。在这里分享一下满分题解及思路,帮大家避避坑。#include<iostream>#include<stdio.h>#include<queue>#include<cstring>#inc......
  • syoj.1827. 线段传送带题解
    前情提要-三分1827.线段传送带P2571[SCOI2010]传送带省流:三分套三分。在二维平面上有两个传送带,一个从A点到B点,一个从C点到D点,速度分别是p和q,在平面内其他点的速度为r。求A点到D点的最小速度。考虑从A到D的路程一定是\(AE+EF+FD\),即通过这两个点连......
  • CF1733D1 题解
    原题传送门题目大意给定两个长度为\(n\)的二进制字符串\(a\)和\(b\),你可以进行若干次操作,对于每次操作:选两个数\(l\)和\(r\),且\(l<r\),将\(a_l\)和\(a_r\)交换。如果选取的\(l\)和\(r\)相邻,代价为\(x\),否则为\(y\)。保证\(y≤x\),求出最小代价使得\(a=......
  • CF1191B 题解
    原题传送门题目大意\(3\)块麻将,求需要换掉几张牌才能一次出完\(3\)块麻将。每块麻将,用一个长度为\(2\)的字符串给出,字符串由\((1,9)\)的一位数字和\(m\)、\(s\)或\(p\)组成。\(3\)块一模一样的麻将或第\(2\)位相同,前面是连号的\(3\)块麻将都可以一次性出完。......
  • CF175B 题解
    原题传送门题目大意如题目描述。思路分析\(1≤n≤1000\),很明显\(\mathcal{O(n^2)}\)不超时,使用结构体,暴力即可。利用双循环求出名字相同的结构体并判断最高分,再根据字典序排序,再双循环求出比自己优秀人数,输出即可。代码:/*Writtenbysmx*/#include<bits/stdc++.h>usin......
  • Atcoder ABC 333 题解(A - F)
    ABC不讲D待更E待更F设$f(i,j)$为有$i$个人时,第$j$个人活到最后的概率,显然:\[f(i,j)=\begin{cases}1,&i=1,j=1\\\frac{1}{2}f(i,i),&i\neq1,j=1\\\frac{1}{2}f(i,j-1)+\frac{1}{2}f(i-1,j-1),&i\neq1,2\lej......
  • Queries for the Array 题解
    前言这场CF是我赛后打的,vp赛时没做出来,后来发现是有个地方理解错了,有一些细节没有考虑到。现在换了一种思路来写,感觉更清晰了。做法首先需要动态维护三个变量,\(cnt\)和\(finishsort\)和\(unfinishsort\)。这三个变量分别表示当前数字的个数,已经排好序的最后一个位置,和没......
  • poker 题解
    原题链接:poker赛时只有\(40\)分,改完之后感觉是一道好题,于是就来写篇题解。题意有\(k\)张扑克牌,\(n\)种数字,每张牌都有两面,每一面分别写了一个数字,你可以选择打出这张牌的任意一面,但是不能两面同时打,也可以选择不打这张牌。有\(q\)个询问,每个询问给定\(l\)和\(r\),判断......
  • P3694 邦邦的大合唱站队 题解
    原题链接:P3694思路状态设计因为这道题\(m\)的范围非常小,所以可以用\(m\)来作为状态。设\(dp_{i}\)表示\(m\)支队伍的状态为\(i\)时最少让多少偶像出列。预处理在转移之前,我们先要预处理出序列的前缀和\(sum_{i,j}\)表示第\(i\)个数之前有多少个值为\(j\)......