• jzoj2701 【GDKOI2012模拟02.01】矩阵


    传送门:https://jzoj.net/senior/#main/show/2701

    【题目大意】

    给出矩阵A,求矩阵B,使得

    最小,矩阵B每个元素在[L,R]内

    n<=200,1<=Aij,L,R<=1000, L<=R

    【题解】

    我们二分答案x,然后对行列建点,每行向每列连[L,R]的边,然后S向每行连[max(S[i]-x), S[i]+x]的边,每列向T连[max(T[i]-x), T[i]+x]的边,判断是否有可行流即可。

    其中S[i]表示A中第i行的和,T[i]表示A中第i列的和。

    判断有源汇上下界可行流:按照无源汇那样建边,多来一条(T->S,[0,inf])即可。

    然后跑dinic,判断从SS流出的边是否全流满。

    # include <queue>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 200 + 10, N = 5e5 + 10, inf = 1e9;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, m, a[M][M], s1[M], s2[M], S, T, L, R;
    int head[M * 4], nxt[N], to[N], flow[N], tot, indeg[M * 4];
    inline void add(int u, int v, int fl) {
        ++tot; nxt[tot] = head[u]; head[u] = tot;
        to[tot] = v; flow[tot] = fl;
    }
    inline void adde(int u, int v, int fl) {
        add(u, v, fl), add(v, u, 0);
    }
    
    inline void tadd(int u, int v, int lf, int rf) {
        adde(u, v, rf-lf);
        indeg[v] += lf;
        indeg[u] -= lf; 
    }
    
    namespace MF {
        queue<int> q;
        
        int c[M * 3], cur[M * 3]; 
        inline bool bfs() {
            for (int i=1; i<=n+m+4; ++i) c[i] = -1;
            while(!q.empty()) q.pop();
            q.push(S); c[S] = 1;
            while(!q.empty()) {
                int top = q.front(); q.pop();
                for (int i=head[top]; i; i=nxt[i]) {
                    if(c[to[i]] != -1 || flow[i] == 0) continue;
                    c[to[i]] = c[top] + 1;
                    q.push(to[i]);
                    if(to[i] == T) return 1;
                }
            }
            return 0;
        }
        
        inline int dfs(int x, int low) {
            if(x == T) return low;
            int r = low, fl;
            for (int i=cur[x]; i; i=nxt[i]) {
                if(c[to[i]] != c[x]+1 || flow[i] == 0) continue;
                fl = dfs(to[i], min(r, flow[i]));
                flow[i] -= fl; flow[i^1] += fl; r -= fl;
                if(flow[i] > 0) cur[x] = i; 
                if(!r) return low;
            }
            if(r == low) c[x] = -1; 
            return low-r;
        }
        
        inline int main() {
            int ans = 0; 
            while(bfs()) {
                for (int i=1; i<=n+m+4; ++i) cur[i] = head[i];
                ans += dfs(S, inf); 
            }
            return ans;
        }
    }
    
    
    
    # define line(x) (x)
    # define row(x) (x+n) 
    
    inline void build(int x) {
        int SS = n+m+1, TT = n+m+2;
        S = n+m+3, T = n+m+4; 
        for (int i=1; i<=n+m+2; ++i) indeg[i] = 0; 
        for (int i=1; i<=n; ++i)
            for (int j=1; j<=m; ++j) 
                tadd(line(i), row(j), L, R); 
        for (int i=1; i<=n; ++i) 
            tadd(SS, line(i), max(0, s1[i]-x), s1[i]+x);
        for (int i=1; i<=m; ++i) 
            tadd(row(i), TT, max(0, s2[i]-x), s2[i]+x);
        tadd(TT, SS, 0, inf); 
        for (int i=1; i<=n+m+2; ++i) {
            if(indeg[i] < 0) adde(i, T, -indeg[i]);
            else adde(S, i, indeg[i]);
        }
    }
    
    inline bool chk(int x) {
        tot = 1; memset(head, 0, sizeof head); 
        build(x);
        MF::main(); 
    //    cout << x << endl;    
        for (int i=head[S]; i; i=nxt[i]) { 
    //        cout << flow[i] << ' '; 
            if(flow[i] != 0) {
    //            cout << endl;
                return false; 
            }
        }
    //    cout << endl;
        return true; 
    }
    
    inline void gans(int ans) {
        for (int i=1; i<=n; ++i, puts("")) {
            for (int j=1; j<=m; ++j) {
                for (int p=head[line(i)]; p; p=nxt[p]) {
                    if(to[p] == row(j)) {
                        printf("%d ", flow[p^1] + L); 
                        break;
                    }
                }
            }
        }
    }
    
    int main() {
        freopen("mat.in", "r", stdin);
        freopen("mat.out", "w", stdout); 
        cin >> n >> m;
        for (int i=1; i<=n; ++i)
            for (int j=1; j<=m; ++j) {
                scanf("%d", &a[i][j]);
                s1[i] += a[i][j];
                s2[j] += a[i][j];
            }
        cin >> L >> R; 
        int l = 0, r = 2e5, mid, ans = 0;
        while(1) {
            if(r-l <= 3) {
                for (int i=l; i<=r; ++i)
                    if(chk(i)) {
                        ans = i;
                        break;
                    }
                break;
            }
            mid = l+r>>1;
            if(chk(mid)) r = mid;
            else l = mid;
        }
        cout << ans << endl;
        gans(ans); 
        return 0;
    }
    View Code
  • 相关阅读:
    ThinkPHP 3.2.2 实现持久登录 ( 记住我 )
    Java实现 LeetCode 20 有效的括号
    Java实现 LeetCode 20 有效的括号
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 17 电话号码的字母组合
  • 原文地址:https://www.cnblogs.com/galaxies/p/jzoj2701.html
Copyright © 2020-2023  润新知