zoukankan      html  css  js  c++  java
  • 【BZOJ-3996】线性代数 最小割-最大流

    3996: [TJOI2015]线性代数

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1054  Solved: 684
    [Submit][Status][Discuss]

    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

    Solution

    首先来化简一下题目中的式子:

    设$E=A*B$,很显然E为一个1×N的矩阵,那么有$E_{1,j}=sum_{i=1}^{N}A_{1,i}B_{i,j}$

    那么$A*B-C$就可以化成$F_{1,j}=sum_{i=1}^{N}A_{1,i}B_{i,j}-C_{1,j}$

    那么进一步化简$D_{1,1}=sum_{j=1}^{N}left ( left ( sum_{i=1}^{N}A_{1,i}B_{i,j}-C_{1,j} ight )*A'_{j,1} ight )$

    最后化成:$D=sum_{i=1}^{N}sum_{j=1}^{N}A_{i}A_{j}B_{i,j}-sum_{i=1}^{N}A_{i}C_{i}$

    那么从式子的角度去思考建图由于$A$是一个0/1矩阵,不妨把$A$看做“选”或“不选”,那么$B_{i,j}$看做同时选$i$和$j$两个物品的收益,$C_{i}$可以看做选第$i$个物品的代价。 

    也就是说选$B_{i,j}$必须选$C_{i},C_{j}$

    最大权闭合子图.....

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-')f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define maxn 300010
    #define maxm 3000010
    int N,tot,ans;
    struct Edgenode{int to,next,cap;}edge[maxm];
    int head[maxn],cnt=1;
    void add(int u,int v,int w)
    {cnt++;edge[cnt].to=v;edge[cnt].cap=w;edge[cnt].next=head[u];head[u]=cnt;}
    void insert(int u,int v,int w)
    {add(u,v,w);add(v,u,0);}
    //
    #define inf 0x7fffffff
    int dis[maxn],q[maxn<<1],cur[maxn],S,T;
    bool bfs()
    {
        for (int i=S; i<=T; i++) dis[i]=-1;
        q[0]=S; int he=0,ta=1;
        while (he<ta)
            {
                int now=q[he++];
                for (int i=head[now]; i; i=edge[i].next)
                    if (edge[i].cap && dis[edge[i].to]==-1)
                        dis[edge[i].to]=dis[now]+1,q[ta++]=edge[i].to;
            }
        return dis[T]!=-1;
    }
    int dfs(int loc,int low)
    {
        if (loc==T) return low;
        int w,used=0;
        for (int i=cur[loc]; i; i=edge[i].next)
            if (edge[i].cap && dis[edge[i].to]==dis[loc]+1)
                {
                    w=dfs(edge[i].to,min(low-used,edge[i].cap));
                    edge[i].cap-=w; edge[i^1].cap+=w;
                    used+=w; if (edge[i].cap) cur[loc]=i;
                    if (used==low) return low;
                }
        if (!used) dis[loc]=-1;
        return used;
    }
    int dinic()
    {
        int tmp=0;
        while (bfs())
            {
                for (int i=S; i<=T; i++) cur[i]=head[i];
                tmp+=dfs(S,inf);
            }
        return tmp;
    }
    //
    int main()
    {
        N=read(); S=0,T=N+N*N+1;
        for (int i=1; i<=N; i++)
            for (int x,j=1; j<=N; j++)
                x=read(),tot+=x,insert((i-1)*N+j+N,T,x),
                insert(i,(i-1)*N+j+N,inf),insert(j,(i-1)*N+j+N,inf);
        for (int x,i=1; i<=N; i++)
            x=read(),insert(S,i,x);
        ans=dinic();
        printf("%d
    ",tot-ans);
        return 0;
    }

    正解被喝水路过的ShallWe直接秒....不然我还没往最小割模型上靠...

  • 相关阅读:
    Ubuntu16.04下搭建LAMP环境
    关于下载SAE日志签名认证的方法——PHP版
    时隔这么长时间,又回来写博客了
    转战网站后台与python
    学习之路
    周末随笔
    Shell基础-环境变量配置文件
    关于骑行
    MYSQL 8.0 linux安装步骤
    一个golang项目笔记 (二) 动态加载库
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5363781.html
Copyright © 2011-2022 走看看