zoukankan      html  css  js  c++  java
  • MUTC 1 D Matrix 线性代数 网络流

    Matrix

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 825    Accepted Submission(s): 212


    Problem Description
    Let A be a 1*N matrix, and each element of A is either 0 or 1. You are to find such A that maximize D=(A*B-C)*AT, where B is a given N*N matrix whose elements are non-negative, C is a given 1*N matrix whose elements are also non-negative, and AT is the transposition of A (i.e. a N*1 matrix).
     

    Input
    The first line contains the number of test cases T, followed by T test cases.
    For each case, the first line contains an integer N (1<=N<=1000).
    The next N lines, each of which contains N integers, illustrating the matrix B. The jth integer on the ith line is B[i][j].
    Then one line followed, containing N integers, describing the matrix C, the ith one for C[i].
    You may assume that sum{B[i][j]} < 2^31, and sum{C[i]} < 2^31.
     

    Output
    For each case, output the the maximum D you may get.
     

    Sample Input
    1 3 1 2 1 3 1 0 1 2 3 2 3 7
     

    Sample Output
    2
    Hint
    For sample, A=[1, 1, 0] or A=[1, 1, 1] would get the maximum D.
     

    Author
    BUPT
     

    Source
     

    Recommend
    zhuyuanchen520
     

    -----------------------

    转自苟大神的博客

    题目:Matrix

     

    之所以能够用最大流解决这个问题,关键在于最大流可以求解下面这个函数的最小值:

    接下来就分析一下如何用最大流求解上面这个函数的极值。

    首先xi一共只有两种选择,那么最终可以按xi的取值将xi划分成两个集合,那么如果xi在值为1的集合里,xj在值为0的集合里,那么就会

    产生一个代价cij。同时如果xi选择0就会产生一个bi的代价,如果xi选择1就会产生一个ai的代价。于是构造一个源点S,汇点T做最小

    割,不妨假设做完最小割之后值为1的xi的集合是和S相连的部分,值为0的xi的集合是和T相连的部分。

     

    由于表达式中有三项,我们用三种割边来分别描述这三项的值。一种是xi选择了1,这样就不能选择0,需要把xi-T这条边割掉,由于xi

    选择1会产生ai的代价,那么就把这条边的容量设为ai。另一种是xi选择了0,这样就不能选择1,需要把S-xi这条边割掉,由于xi选择0会

    产生bi的代价,那么就把这条边的容量设为bi。最后一种是xi选择了1,xj选择了0,这样xi和xj不能在同一个集合中,需要把xi-xj这条边割

    掉,由于xi选择1,xj选择0产生cij的代价,那么就把这条边的容量设为cij。这样对建好的图做最小割就可以得到上面哪个函数的最小

    值。

     

    接着我们分析这个题目如何转化成上面这种模型。首先我们将D的表达式赤裸裸地写出来:


    这种形式必然不能看出来和上面那个表达式有什么关系,于是我们继续将其化简:

    如果令f等于最后一行括号里的内容,那么发生了什么?如果ai选择0会产生sum{bij}(1<=j<=N)的代价,如果ai选择1会产生ci的代价,如

    果ai选择1且aj选择0就会产生bij的代价。这样就完全转化成了上面的模型。

    ----------------------

    白书上的模板效率果然非常低

    ----------------------

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    
    using namespace std;
    
    const int maxn=2222;
    const int maxm=2222222;
    const int INF=1e9;
    
    struct Edge{
        int from,to,cap,flow;
    };
    
    struct Dinic{
        int n,m,s,t;
        vector<Edge>edges;
        vector<int>G[maxn];
        bool vis[maxn];
        int d[maxn];
        int cur[maxn];
    
        void init(int n,int s,int t){
            this->n=n;
            this->s=s;
            this->t=t;
            for (int i=0;i<n;i++) G[i].clear();
            edges.clear();
            m=0;
        }
    
        void addedge(int from,int to,int cap){
            edges.push_back((Edge){from,to,cap,0});
            edges.push_back((Edge){to,from,0,0});
            m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool BFS(){
            memset(vis,0,sizeof(vis));
            queue<int>que;
            que.push(s);
            d[s]=0;
            vis[s]=true;
            while (!que.empty()){
                int x=que.front();que.pop();
                for (int i=0;i<G[x].size();i++){
                    Edge& e=edges[G[x][i]];
                    if (!vis[e.to]&&e.cap>e.flow){
                        vis[e.to]=true;
                        d[e.to]=d[x]+1;
                        que.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int DFS(int x,int a){
            if (x==t||a==0) return a;
            int flow=0,f;
            for (int& i=cur[x];i<G[x].size();i++){
                Edge& e=edges[G[x][i]];
                if (d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){
                    e.flow+=f;
                    edges[G[x][i]^1].flow-=f;
                    flow+=f;
                    a-=f;
                    if (a==0) break;
                }
            }
            return flow;
        }
    
        long long Maxflow(int s,int t){
            this->s=s;
            this->t=t;
            long long flow=0;
            while (BFS()){
                memset(cur,0,sizeof(cur));
                flow+=DFS(s,INF);
            }
            return flow;
        }
    
    }solver;
    
    int b[maxn][maxn];
    int c[maxn];
    
    int main()
    {
        int T,n,s,t,a,x;
        long long sum;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d",&n);
            s=0;
            t=n+1;
            solver.init(n+2,s,t);
            sum=0;
            for (int i=1;i<=n;i++)
            {
                a=0;
                for (int j=1;j<=n;j++)
                {
                    scanf("%d",&x);
                    a+=x;
                    solver.addedge(i,j,x);
                }
                sum+=a;
                solver.addedge(s,i,a);
            }
            for (int i=1;i<=n;i++)
            {
                scanf("%d",&x);
                solver.addedge(i,t,x);
            }
            printf("%I64d\n",sum-solver.Maxflow(s,t));
        }
        return 0;
    }
    





  • 相关阅读:
    oracle创建函数和调用存储过程和调用函数的例子(区别)
    oracle存储过程的创建和使用
    oracle恢复已删除数据
    存储管理工具StorageExplorer的基本使用
    Azure CLI对ASM,ARM资源的基本操作
    Windows系统安装Azure CLI
    Azure Powershell对ASM资源的基本操作
    Azure Powershell对ARM资源的基本操作
    安装Windows Azure Powershell
    Linux虚拟机之间实现密钥登陆
  • 原文地址:https://www.cnblogs.com/cyendra/p/3226310.html
Copyright © 2011-2022 走看看