zoukankan      html  css  js  c++  java
  • BZOJ_3996_[TJOI2015]线性代数_最大权闭合子图

    BZOJ_3996_[TJOI2015]线性代数_最大权闭合子图

    Description

    给出一个N*N的矩阵B和一个1*N的矩阵C。求出一个1*N的01矩阵A.使得

    D=(A*B-C)*A^T最大。其中A^T为A的转置。输出D

    Input

    第一行输入一个整数N,接下来N行输入B矩阵,第i行第J个数字代表Bij.
    接下来一行输入N个整数,代表矩阵C。矩阵B和矩阵C中每个数字都是不超过1000的非负整数。

    Output

    输出最大的D

    Sample Input

    3
    1 2 1
    3 1 0
    1 2 3
    2 3 7

    Sample Output

    2

    HINT

     1<=N<=500


    根据乘法分配律可知,对于$b(i,j)$ ,只有$a[i],a[j]$ 都选才会有贡献。

    而选择$a[j]$会导致选择$-c[j]$.

    可以发现这是个最大权闭合子图的模型。

    $S->b[i][j],b[i][j]->c[i],b[i][j]->c[j],c[i]->T$

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 300050
    #define M 2000050
    #define inf 100000000
    int head[N],to[M],nxt[M],flow[M],cnt=1,sum,n;
    int dep[N],Q[N],l,r,S,T,idx[510][510],c[510];
    inline void add(int u,int v,int f) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f;
        to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0;
    }
    bool bfs() {
        memset(dep,0,sizeof(dep));
        l=r=0;Q[r++]=S;dep[S]=1;
        while(l<r) {
            int x=Q[l++],i;
            for(i=head[x];i;i=nxt[i]) {
                if(!dep[to[i]]&&flow[i]) {
                    dep[to[i]]=dep[x]+1;
                    if(to[i]==T) return 1;
                    Q[r++]=to[i];
                }
            }
        }
        return 0;
    }
    int dfs(int x,int mf) {
        if(x==T) return mf;
        int i,nf=0;
        for(i=head[x];i;i=nxt[i]) {
            if(dep[to[i]]==dep[x]+1&&flow[i]) {
                int tmp=dfs(to[i],min(mf-nf,flow[i]));
                if(!tmp) dep[to[i]]=0;
                nf+=tmp;
                flow[i]-=tmp;
                flow[i^1]+=tmp;
                if(nf==mf) break;
            }
        }
        return nf;
    }
    void dinic() {
        int f;
        while(bfs()) while(f=dfs(S,inf)) sum-=f;
        printf("%d
    ",sum);
    }
    int main() {
        int i,j,x;
        scanf("%d",&n);
        S=n*n+n+1;T=S+1;
        int tot=0;
        for(i=1;i<=n;i++) {
            for(j=1;j<=n;j++) {
                idx[i][j]=++tot;
                scanf("%d",&x);
                sum+=x;
                add(S,tot,x);
            }
        }
        for(i=1;i<=n;i++) {
            scanf("%d",&c[i]);
            add(i+n*n,T,c[i]);
        }
        for(i=1;i<=n;i++) {
            for(j=1;j<=n;j++) {
                add(idx[i][j],n*n+i,inf);
                add(idx[i][j],n*n+j,inf);
            }
        }
        dinic();
    }
    
  • 相关阅读:
    从函数作用域和块级作用域看javascript的作用域链
    基于vue实现一个简单的MVVM框架(源码分析)
    发布-订阅模式
    希尔排序
    直接插入排序
    选择排序
    React Fiber源码分析 第三篇(异步状态)
    React Fiber源码分析 第二篇(同步模式)
    React Fiber源码分析 第一篇
    数据结构 之 树总结
  • 原文地址:https://www.cnblogs.com/suika/p/8998171.html
Copyright © 2011-2022 走看看