• BZOJ 3996 线性代数 最小割


    题意:

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

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

    分析:

      这道题比较绕,我们需要看清题目中那个式子的本质。A*B的贡献是正的,说明这是价值。C的贡献是负的,说明这是代价。

      仔细理解这句话“只有ai和aj同时为1的时候,才对答案有bij的贡献。使ai为1的代价为ci”

      我们现在是否能从题目中的式子中提炼出这个关系?如果能,请继续

      为什么说这题是最小割呢?因为,这里有新的两个字,当我们面临这两个字时,就要考虑最小割,那就是“取舍

      在这道题的意志中,我们需要选择舍弃b带来的相应价值,以此来避免付出代价,或者是为了获得价值,而选择舍弃而付出相应的代价。所以我们建图为两部分:

      左半部分,有n^2个点,(可以理解是我们抽象出的b数组)从原点向(i,j)点连容量为bij的边,右半部分有n个点,i号点向汇点连一条容量为ci的边。

      点(i,j)右边的点i和j分别连容量为inf的边。

      这样呢,我们的限制就是,要么舍弃bij这个价值,要么付出ci和cj的代价,对于每个点都是这样,最小割,就是我们最少舍弃的贡献。然后,我们求出b数组的价值和,减去最小割就是我们最终获得的最大贡献。

    代码:

     1 #include<bits/stdc++.h>
     2 #define ms(a,x) memset(a,x,sizeof(a)) 
     3 using namespace std;int tot=0;
     4 const int N=1000005,M=505,inf=0x3f3f3f3f;
     5 int S,T,n,m,k,h[N],c=1,q[N],d[N],b[M][M],C[M];
     6 struct node{int y,z,nxt;}e[N*4];
     7 void add(int x,int y,int z){
     8     e[++c]=(node){y,z,h[x]};h[x]=c;
     9     e[++c]=(node){x,0,h[y]};h[y]=c;
    10 } bool bfs(){
    11     int f=1,t=0;ms(d,-1);
    12     q[++t]=S;d[S]=0;
    13     while(f<=t){
    14         int x=q[f++];
    15         for(int i=h[x],y;~i;i=e[i].nxt)
    16         if(d[y=e[i].y]==-1&&e[i].z) 
    17         d[y]=d[x]+1,q[++t]=y;
    18     } return (d[T]!=-1);
    19 } int dfs(int x,int f){
    20     if(x==T) return f;int w,tmp=0;
    21     for(int i=h[x],y;~i;i=e[i].nxt)
    22     if(d[y=e[i].y]==d[x]+1&&e[i].z){
    23         w=dfs(y,min(e[i].z,f-tmp));
    24         if(!w) d[y]=-1;e[i].z-=w;
    25         e[i^1].z+=w;tmp+=w;
    26         if(tmp==f) return f;
    27     } return tmp;
    28 } void dinic(){
    29     while(bfs()) tot+=dfs(S,inf);
    30 } int main(){
    31     scanf("%d",&n);S=0,T=n*n+n+10;
    32     int sm=0,nm=0;ms(h,-1);
    33     for(int i=1;i<=n;i++)
    34     for(int j=1;j<=n;j++)
    35     scanf("%d",&b[i][j]);
    36     for(int i=1;i<=n;i++)
    37     scanf("%d",&C[i]),add(i+n*n,T,C[i]);
    38     for(int i=1;i<=n;i++)
    39     for(int j=1;j<=n;j++)
    40     sm+=b[i][j],add(S,++nm,b[i][j]),
    41     add(nm,i+n*n,inf),add(nm,j+n*n,inf);
    42     dinic();sm-=tot;
    43     printf("%d
    ",sm);
    44     return 0;
    45 }
    最小割
  • 相关阅读:
    FileUpload1上传控件
    docker如何push镜像到docker hub个人的仓库
    docker的ubuntu镜像无ifconfig和ping命令
    keystone同步数据库的时候提示error
    openstack安装dashboard后访问horizon出错 500 or 504
    装了ubuntu之后,只能进入ubuntu系统,不能进入windows系统
    Kernal Panic
    无法获得锁 /var/lib/dpkg/lock -open
    用户 'NT AUTHORITYIUSR' 登录失败
    配置错误:不能在此路径中使用此配置节。
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10252288.html
Copyright © 2020-2023  润新知