• 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

    Source

    经过推导得出:


    是一个最大权闭合子图的模型

    选择一个Ai==1,会损失Ci;

    对于一个点对(i,j),当Ai和Aj同时==1时,可以获得Bij的收益;

    由于收益是同时依赖于两个点的,所以可以对每一个点对新建一个附加点tt,从s向其连Bij的边,然后tt向i,j连Inf;

    其余的连边就是最大权闭合子图的套路了

    最后正权和-最小割即为答案

    (玄学剪枝真有用)

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #define RG register
    using namespace std;
    typedef long long ll;
    const int N=2000000;
    const int Inf=19260817;
    int gi()
    {
      int x=0;
      char ch=getchar();
      while(ch<'0'||ch>'9') ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
      return x;
    }
    int head[N],nxt[N],to[N],s[N],cnt=1,S,T,n,sum,q[N],level[N],vis[N],F,c[N];
    int b[600][600],C[1000],tot;
    inline void Addedge(int x,int y,int z) {
      to[++cnt]=y,s[cnt]=z,nxt[cnt]=head[x],head[x]=cnt;
    }
    inline void lnk(int x,int y,int z){
      Addedge(x,y,z);Addedge(y,x,0);
    }
    inline bool bfs(){
      for(RG int i=S;i<=T;i++) level[i]=0,vis[i]=0;
      int t=0,sum=1;
      q[0]=S,level[S]=1,vis[S]=1;
      while(t<sum){
          int now=q[t++];
          if(now==T) return 1;
          for(RG int i=head[now];i;i=nxt[i]){
          int y=to[i];
          if(level[y]==0&&s[i]){
              level[y]=level[now]+1;
              q[sum++]=y;
            }
        }
        }
      return 0;
    }
    inline int dfs(int now,int maxf){
      if(now==T) return maxf;
      int ret=0;
      for(RG int i=head[now];i;i=nxt[i]) {
        int y=to[i],f=s[i];
        if(level[y]==level[now]+1&&f) {
          int minn=min(maxf-ret,f);
          f=dfs(y,minn);
          s[i]-=f;
          s[i^1]+=f;ret+=f;
          if(ret==maxf) break;
        }
      }
      if(!ret) level[now]=0;
      return ret;
    }
    inline void Dinic(){
        while(bfs()) F+=dfs(S,Inf);
    }
    int main(){
        n=gi();
        for(RG int i=1;i<=n;i++)
        for(RG int j=1;j<=n;j++) b[i][j]=gi();
        for(RG int i=1;i<=n;i++) C[i]=gi(),tot+=C[i];
        S=0,T=n+n*n+1;int ans=0,tt=n;
        for(RG int i=1;i<=n;i++) lnk(i,T,C[i]);
        for(RG int i=1;i<=n;i++){
        for(RG int j=1;j<=n;j++){
            tt++;lnk(S,tt,b[i][j]);ans+=b[i][j];
            lnk(tt,i,Inf);lnk(tt,j,Inf);
        }
        }
        Dinic();printf("%d
    ",ans-F);
        return 0;
    }
    

      

  • 相关阅读:
    Linux内核从原理到代码详解
    linux内核研究-8-块设备I/O层
    《Linux内核分析》课程总结
    Nginx 重写规则指南1
    Nginx初探
    Nginx源码分析:3张图看懂启动及进程工作原理
    nginx源码分析 +redis的那些事儿
    I/O 模型及其设计模式
    高并发性能调试经验分享
    myawr
  • 原文地址:https://www.cnblogs.com/qt666/p/6824620.html
Copyright © 2020-2023  润新知