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;
}





posted on 2013-05-29 08:03  电子幼体  阅读(186)  评论(0编辑  收藏  举报

导航