Matrix
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 825 Accepted Submission(s): 212
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.
1 3 1 2 1 3 1 0 1 2 3 2 3 7
2HintFor sample, A=[1, 1, 0] or A=[1, 1, 1] would get the maximum D.
转自苟大神的博客
之所以能够用最大流解决这个问题,关键在于最大流可以求解下面这个函数的最小值:
接下来就分析一下如何用最大流求解上面这个函数的极值。
首先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;
}