1. 程式人生 > >BZOJ 3996 TJOI2015 線性代數 網路流

BZOJ 3996 TJOI2015 線性代數 網路流

題目大意:給定一個nn的矩陣B和一個1n的行向量C,求一個1n的01矩陣A,使(A×BC)×AT最大
(A×BC)×AT=A×B×ATC×AT
我們可以考慮有n個物品,每個物品選不選對應A中每個位置是1還是0
那麼行向量C可以看做每個物品的代價 而矩陣B可以看做同時選擇某兩個物品時的收益
那麼這個模型就被我們直接分析出來了,網路流走起~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
#define S 0
#define T (M-1) #define INF 0x3f3f3f3f using namespace std; int n; long long ans; namespace Max_Flow{ struct abcd{ int to,f,next; }table[2002002]; int head[M],tot=1; int dpt[M]; void Add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next
=head[x]; head[x]=tot; } void Link(int x,int y,int z) { Add(x,y,z);Add(y,x,0); } bool BFS() { static int q[M]; int i,r=0,h=0; memset(dpt,-1,sizeof dpt); q[++r]=S;dpt[S]=1; while(r!=h) { int x=q[++h]; for
(i=head[x];i;i=table[i].next) if(table[i].f&&!~dpt[table[i].to]) { dpt[table[i].to]=dpt[x]+1; q[++r]=table[i].to; if(table[i].to==T) return true; } } return false; } int Dinic(int x,int flow) { int i,left=flow; if(x==T) return flow; for(i=head[x];i&&left;i=table[i].next) if(table[i].f&&dpt[table[i].to]==dpt[x]+1) { int temp=Dinic(table[i].to,min(left,table[i].f)); left-=temp; table[i].f-=temp; table[i^1].f+=temp; } if(left) dpt[x]=-1; return flow-left; } } int main() { using namespace Max_Flow; int i,j,x; cin>>n; for(i=1;i<=n;i++) for(j=1;j<=n;j++) { scanf("%d",&x); ans+=x; Link(S,i*n+j,x); Link(i*n+j,i,INF); Link(i*n+j,j,INF); } for(i=1;i<=n;i++) { scanf("%d",&x); Link(i,T,x); } while( BFS() ) ans-=Dinic(S,INF); cout<<ans<<endl; return 0; }