题意:给定一个n*n(n<=1000)的B矩阵和1*n的C矩阵,现在想找到合适的1*n的A矩阵,使得D = (A * B - C) * AT的值最大。
第一项是定值,题目转换为要最小化后面的三项之和,抽象到最小割模型求解。
建图,令源为s,汇为t,中间有n个点。点i到j有一条容量为B[i][j]的边,同时s到点i有一条容量为C[i]的边,点i到t有一条容量为sum{j}B[i][j]的边。
这样,图的任意一个割就与一个A一一对应,最小割即为最小的后面三项之和。简单解释下任意一个割与一个A一一对应:
首先明确后三项即为在B矩阵中所有sigma Bij(A[i] == 0 || A[j] == 0),所以对于任意一点i,s - i (A[i] == 1)或者i - t(A[i] == 0)必选其中之一,如果A[i] == 1则对于所有j(A[j]== 0)来说,存在s – j – i – t的增广路,所以j– i就一定要包含在该割内,对应即为B[j][i],所以任意一个割与一个A一一对应。
Sure原创,转载请注明出处。
#include <iostream> #include <cstdio> #include <memory.h> using namespace std; const int inf = 1 << 29; const int maxn = 1010; const int maxe = 2100000; struct node { int v,w; int next; }edge[maxe]; int head[maxn],cur[maxn],dis[maxn],gap[maxn],pre[maxn]; int B[maxn][maxn],C[maxn],D[maxn]; int n,s,t,idx,sum; void init() { memset(head,-1,sizeof(head)); memset(D,0,sizeof(D)); scanf("%d",&n); s = idx = sum = 0; t = n + 1; return; } void addedge(int u,int v,int w) { edge[idx].v = v; edge[idx].w = w; edge[idx].next = head[u]; head[u] = idx++; edge[idx].v = u; edge[idx].w = 0; edge[idx].next = head[v]; head[v] = idx++; return; } void read() { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&B[i][j]); D[j] += B[i][j]; if(i != j) addedge(i,j,B[i][j]); } } for(int i=1;i<=n;i++) { scanf("%d",&C[i]); addedge(s,i,C[i]); addedge(i,t,D[i]); sum += D[i]; } return; } int isap(int N) { memset(gap,0,sizeof(gap)); memset(dis,0,sizeof(dis)); for(int i=0;i<N;i++) { cur[i] = head[i]; } int i,top = s; int maxflow = 0,flow = inf; gap[s] = N; while(dis[s] < N) { for(i=cur[top];i != -1;i=edge[i].next) { if(edge[i].w > 0 && dis[top] == dis[edge[i].v] + 1) { break; } } if(i != -1) { cur[top] = i; if(edge[i].w < flow) { flow = edge[i].w; } top = edge[i].v; pre[top] = i; if(top == t) { maxflow += flow; while(top != s) { edge[pre[top]].w -= flow; edge[pre[top]^1].w += flow; top = edge[pre[top]^1].v; } flow = inf; } } else { if(--gap[dis[top]] == 0) { break; } cur[top] = head[top]; dis[top] = N; for(int j=head[top];j != -1;j=edge[j].next) { if(edge[j].w > 0 && dis[top] > dis[edge[j].v] + 1) { cur[top] = j; dis[top] = dis[edge[j].v] + 1; } } gap[dis[top]]++; if(top != s) { top = edge[pre[top]^1].v; } } } return maxflow; } int main() { int cas; scanf("%d",&cas); while(cas--) { init(); read(); printf("%d\n",sum - isap(t+1)); } return 0; }