您的位置:首页 > 其它

hdoj 4307 Matrix 【最大流 求解矩阵乘最值】【经典构图!】

2015-09-06 16:00 429 查看

Matrix

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 1573 Accepted Submission(s): 445



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
HintFor sample, A=[1, 1, 0] or A=[1, 1, 1] would get the maximum D.




用【】表示矩阵。

题意:给出公式【D】 = (【A】 * 【B】 - 【C】)* 【AT】。

其中【B】是一个N*N的矩阵,【C】是一个1*N的矩阵,题中均以给出。

【A】是一个1*N的矩阵且里面元素只有0和1,【AT】是矩阵【A】的变化,是一个N*1的矩阵。

现在让你找到一个【A】使得最后结果最大,并输出最大结果。

ORZ大牛

转自:原文出处

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



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

首先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的代价。这样就完全转化成了上面的模型,具体的做法就不再重复说明了。

AC代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define MAXN 1010
#define MAXM 3000000
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int from, to, cap, flow, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int dist[MAXN], cur[MAXN];
bool vis[MAXN];
int N;
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int w)
{
    Edge E1 = {u, v, w, 0, head[u]};
    edge[edgenum] = E1;
    head[u] = edgenum++;
    Edge E2 = {v, u, 0, 0, head[v]};
    edge[edgenum] = E2;
    head[v] = edgenum++;
}
int sum;//记录矩阵B中所有元素之和
int source, sink;
void getMap()
{
    init();
    scanf("%d", &N);
    int a;
    sum = 0;
    source = 0, sink = N+1;
    //B矩阵 构图
    for(int i = 1; i <= N; i++)
    {
        int sumcul = 0;
        for(int j = 1; j <= N; j++)
        {
            scanf("%d", &a);
            sumcul += a;
            sum += a;
            addEdge(i, j, a);
        }
        addEdge(source, i, sumcul);
    }
    //C矩阵 构图
    for(int i = 1; i <= N; i++)
    {
        scanf("%d", &a);
        addEdge(i, sink, a);
    }
}
bool BFS(int s, int t)
{
    queue<int> Q;
    memset(dist, -1, sizeof(dist));
    memset(vis, false, sizeof(vis));
    dist[s] = 0;
    vis[s] = true;
    Q.push(s);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            Edge E = edge[i];
            if(!vis[E.to] && E.cap > E.flow)
            {
                dist[E.to] = dist[u] + 1;
                if(E.to == t) return true;
                vis[E.to] = true;
                Q.push(E.to);
            }
        }
    }
    return false;
}
int DFS(int x, int a, int t)
{
    if(x == t || a == 0) return a;
    int flow = 0, f;
    for(int &i = cur[x]; i != -1; i = edge[i].next)
    {
        Edge &E = edge[i];
        if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap-E.flow), t)) > 0)
        {
            edge[i].flow += f;
            edge[i^1].flow -= f;
            flow += f;
            a -= f;
            if(a == 0) break;
        }
    }
    return flow;
}
int Maxflow(int s, int t)
{
    int flow = 0;
    while(BFS(s, t))
    {
        memcpy(cur, head, sizeof(head));
        flow += DFS(s, INF, t);
    }
    return flow;
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        getMap();
        printf("%d\n", sum - Maxflow(source, sink));
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: