• 有源汇上下界可行流(POJ2396)


    题意:给出一个n*m的矩阵的每行和及每列和,还有一些格子的限制,求一组合法方案。

    源点向行,汇点向列,连一条上下界均为和的边。

    对于某格的限制,从它所在行向所在列连其上下界的边。

    求有源汇上下界可行流即可。

    具体做法可以从汇点向源点连容量为正无穷的边,转成无源汇上下界可行流。

    然后可以新建超级源汇,对于一条下界为l,上界为r的边(x,y),从超级源点向y,x向超级汇点连容量为l的边,x向y连容量为r-l的边。

    如果那些容量为l的边没满流,则无解。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    const int inf = 0x3f3f3f3f, N = 230, M = 25000;
    char op[2];
    int q,n,m,c,x,y,z,s,t,S,T,e=1,fr,l[205][25],r[205][25],ans[205][25],hd[N],nxt[M],to[M],f[M],ch[N];
    void add(int x, int y, int z) {
        to[++e] = y, f[e] = z, nxt[e] = hd[x], hd[x] = e;
        to[++e] = x, f[e] = 0, nxt[e] = hd[y], hd[y] = e;
    }
    void upd(int x, int y) {
        if(op[0] == '<') r[x][y] = min(r[x][y], z-1);
        else if(op[0] == '>') l[x][y] = max(l[x][y], z+1);
        else l[x][y] = max(l[x][y], z), r[x][y] = min(r[x][y], z);
    }
    
    bool tel() {
        memset(ch, -1, sizeof ch);
        queue<int> q;
        q.push(S), ch[S] = 0;
        while(!q.empty()) {
            int u = q.front(); q.pop();
            for(int i = hd[u]; i; i = nxt[i]) if(ch[to[i]] == -1 && f[i]) ch[to[i]] = ch[u]+1, q.push(to[i]);
        }
        return ch[T] != -1;
    }
    int zng(int a, int b) {
        if(a == T) return b;
        int r = 0;
        for(int i = hd[a]; i && b > r; i = nxt[i]) if(ch[to[i]] == ch[a]+1 && f[i]) {
            int rr = zng(to[i], min(b-r, f[i]));
            f[i] -= rr, f[i^1] += rr, r += rr;
        }
        if(!r) ch[a] = -1;
        return r;
    }
    
    int main() {
        scanf("%d", &q);
        while(q--) {
            e = 1;
            memset(hd, 0, sizeof hd);
            memset(l, 0, sizeof l);
            memset(r, 0x3f, sizeof r);
            scanf("%d%d", &n, &m), t = n+m+1, S = n+m+2, T = n+m+3, add(t,s,inf);
            for(int i = 1; i <= n; i++) scanf("%d", &x), add(S,i,x), add(s,T,x);
            for(int i = 1; i <= m; i++) scanf("%d", &x), add(S,t,x), add(i+n,T,x);
            scanf("%d", &c);
            while(c--) {
                scanf("%d%d%s%d", &x, &y, op, &z);
                if(!x && !y) {
                    for(int i = 1; i <= n; i++)
                    for(int j = 1; j <= m; j++)
                        upd(i,j);
                } else if(!x) {
                    for(int i = 1; i <= n; i++) upd(i,y);
                } else if(!y) {
                    for(int i = 1; i <= m; i++) upd(x,i);
                } else upd(x,y);
            }
            if(fr) puts("");
            fr = 1;
            for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++) {
                if(r[i][j] < l[i][j]) {puts("IMPOSSIBLE"); goto aa;}
                add(i,j+n,r[i][j]-l[i][j]),add(S,j+n,l[i][j]),add(i,T,l[i][j]);
            }
            while(tel()) while(zng(S,inf));
            for(int i = hd[S]; i; i = nxt[i]) if(f[i]) {puts("IMPOSSIBLE"); goto aa;}
            for(int i = 1; i <= n; i++)
            for(int j = hd[i]; j; j = nxt[j])
            if(to[j] > n && to[j] <= n+m) ans[i][to[j]-n] = f[j^1];
            for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                printf("%d%c", ans[i][j]+l[i][j], " 
    "[j==m]);
            aa: ;
        }
        return 0;
    }
  • 相关阅读:
    SQL SERVER 分布式事务(DTC)
    .NET 笔试题--自已作答
    设计模式-观察者模式
    设计模式-迭代器模式
    设计模式-责任链模式
    C#中引用类型和值类型
    另一个 OleDbParameterCollection 中已包含 OleDbParameter 错误分析及解决办法
    R语言笔记-set.seed()函数
    R中的sample函数
    R语言包相关命令
  • 原文地址:https://www.cnblogs.com/juruolty/p/6204025.html
Copyright © 2020-2023  润新知