zoukankan      html  css  js  c++  java
  • [TJOI2015]线性代数(最小割)

    题目描述

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

    D=(A*B-C)*A^T最大。其中A^T为A的转置。输出D
    题解
    观察上面那个式子发现,当一个bij有贡献时当且仅当a[i]=1&&a[j]=1
    且当a[i]=1时会产生-c[i]的贡献。
    然后我naive的以为这是个二元关系最小割。
    其实没那么复杂,我们建立源点向矩阵中的每一个元素连b[i][j]的边,然后每个元素向t连c[i]的边。
    然后(i,j)ij分别连inf的边。
    这样割左边相当于ij至少有一个不选,割右边相当于全选。
    代码
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define N 502
    #define M 260020 
    #define inf 2e9
    using namespace std;
    typedef long long ll;
    queue<int>q;
    typedef long long ll;
    int head[M],deep[M],cur[M],tot=1,n,c[N],b[N][N],top;
    ll sum,ans;
    inline ll rd(){
        ll x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x; 
    }
    struct edge{int n,to,l;}e[N*N*7];
    inline void add(int u,int v,int l){
        e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l;
        e[++tot].n=head[v];e[tot].to=u;head[v]=tot;e[tot].l=0;
    }
    inline bool bfs(int s,int t){
        memset(deep,0,sizeof(deep));
        memcpy(cur,head,sizeof(cur));
        q.push(s);deep[s]=1;
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=head[u];i;i=e[i].n){
                int v=e[i].to;
                if(!deep[v]&&e[i].l){deep[v]=deep[u]+1;q.push(v);}
            }
        }
        return deep[t];
    }
    ll dfs(int u,int t,int l){
        if(u==t||!l)return l;
        ll flow=0,f;
        for(int &i=cur[u];i;i=e[i].n){
            int v=e[i].to;
            if(deep[v]==deep[u]+1&&(f=dfs(v,t,min(l,e[i].l)))){
                e[i].l-=f;e[i^1].l+=f;flow+=f;l-=f;
                if(!l)break;
            }
        }
        return flow;
    }
    int main(){
        n=rd();int s=0,t=n*n+n+1;
        for(int i=1;i<=n;++i)for(int j=1;j<=n;++j){
          b[i][j]=rd(),sum+=b[i][j];++top,add(0,top,b[i][j]);
          add(top,n*n+i,inf);add(top,n*n+j,inf);
        }    
        for(int i=1;i<=n;++i)c[i]=rd(),add(n*n+i,t,c[i]);
        while(bfs(s,t))ans+=dfs(s,t,inf);
        cout<<sum-ans;
        return 0;
    }
     
  • 相关阅读:
    php7与其他版本共存
    centos源码安装mysql5.7
    禁用composer update命令
    lumen怎么得到当前Uri的控制器、Action、路由规则
    配置lumen的log为daily模式
    laravel如何打印orm封装的sql语句
    nginx 重写URL尾部斜杠
    Laravel的Nginx重写规则--让路由支持末尾加斜线
    laravel redis存数组并设置过期时间
    openresty
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10258850.html
Copyright © 2011-2022 走看看