[TJOI2014] [Bzoj3996] 线性代数 [网络流,最小割]
由原式,可以推出D=Σ(i=1,n,Σ(j=1,n,A[i]*A[j]*B[i][j]))-Σ(i=1,n,A[i]*C[i])
$D=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}A[i]*A[j]*B[i][j]-\sum\limits_{i=1}^{n}A[i]*C[i]$
,故建图方法如下:由源点像第一层n*n个点连边,边权为$B[i][j]$,由第一层像第二层连边,边权正无穷,由第二层向汇点连边,边权$C[i]$。最终答案为$\sum B-MAXFLOW$。
推导过程:
(A * B - C) * AT
(1*n) (n*n) (1*n) (n*1)
=A*B * AT - C * AT
(1*n) (n*1) (1*1)
令$P[i][j]=\sum\limits_{k=1}^{n}A[i][k]*B[k][j]$
$A^T[i][j]=A[j][i]=A[i](j=1)$
原式=$\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}A[i]*B[i][j]*A[j]-\sum\limits_{i=1}^{n}A[i]*C[i]$
参考HZWER博客:http://hzwer.com/6814.html
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <algorithm> #include <queue> using namespace std; template<const int _n> struct Edge { struct Edge_base { int to,next,w; }e[_n]; int p[_n],cnt; Edge() { clear(); } int start(const int x) { return p[x]; } void insert(const int x,const int y,const int z) { e[++cnt].to=y; e[cnt].next=p[x]; e[cnt].w=z; p[x]=cnt; return ; } void clear() { cnt=1,memset(p,0,sizeof(p)); } Edge_base& operator[](const int x) { return e[x]; } }; int SSS,TTT,cur[2100000]; int n,tot,level[2100000]; Edge<2100000> e; bool Bfs(const int S) { int i,t; queue<int> Q; memset(level,0,sizeof(int)*(n+n*n+5)); level[S]=1; Q.push(S); while(!Q.empty()) { t=Q.front();Q.pop(); for(i=e.start(t);i;i=e[i].next) { if(!level[e[i].to] && e[i].w) { level[e[i].to]=level[t]+1; Q.push(e[i].to); } } } return level[TTT]; } int Dfs(const int S,const int bk) { if(S==TTT)return bk; int rest=bk; for(int &i=cur[S];i;i=e[i].next) { if(level[e[i].to]==level[S]+1 && e[i].w) { int flow=Dfs(e[i].to,min(rest,e[i].w)); e[i].w-=flow; e[i^1].w+=flow; if((rest-=flow)<=0)break; } } if(bk==rest)level[S]=0; return bk-rest; } int Dinic() { int flow=0; while(Bfs(SSS)) { memcpy(cur,e.p,sizeof(int)*(n+n*n+5)); flow+=Dfs(SSS,0x3f3f3f3f); } return flow; } int getint() { int data=0; char ch=getchar(); while(ch<'0' || ch>'9')ch=getchar(); while(ch>='0' && ch<='9')data=data*10+ch-48,ch=getchar(); return data; } int main() { int i,j,x,Sum=0; n=getint(); tot=n;SSS=tot+n*n+1;TTT=SSS+1; for(i=1;i<=n;++i) { for(j=1;j<=n;++j) { x=getint();++tot; e.insert(SSS,tot,x); e.insert(tot,SSS,0); e.insert(tot,i,0x3f3f3f3f); e.insert(i,tot,0); e.insert(tot,j,0x3f3f3f3f); e.insert(j,tot,0); Sum+=x; } } for(i=1;i<=n;++i) { x=getint(); e.insert(i,TTT,x); e.insert(TTT,i,0); } printf("%d\n",Sum-Dinic()); return 0; }