• 【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直接秒....不然我还没往最小割模型上靠...

  • 相关阅读:
    android loginDemo +WebService用户登录验证
    Integrating Google Sign-In into Your Android App
    Android 应用程序集成Google 登录及二次封装
    facebook 分享
    Android Facebook和Twitter登录和分享完整版
    Android 友盟社会化组件-分享实现
    Android集成友盟社会化分享功能
    c 判断是否为 字母或数字(iswalnum example)
    c 判断字符是否为字母 (iswalpha example)
    下载安装Xocde并创建一个C语言的项目工程
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5363781.html
Copyright © 2020-2023  润新知