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