BZOJ_3996_[TJOI2015]線性代數_最大權閉合子圖
阿新 • • 發佈:2018-05-06
() NPU oid str AD while names content head
1 2 1
3 1 0
1 2 3
2 3 7
BZOJ_3996_[TJOI2015]線性代數_最大權閉合子圖
Description
給出一個N*N的矩陣B和一個1*N的矩陣C。求出一個1*N的01矩陣A.使得
D=(A*B-C)*A^T最大。其中A^T為A的轉置。輸出DInput
第一行輸入一個整數N,接下來N行輸入B矩陣,第i行第J個數字代表Bij. 接下來一行輸入N個整數,代表矩陣C。矩陣B和矩陣C中每個數字都是不超過1000的非負整數。Output
輸出最大的D
Sample Input
31 2 1
3 1 0
1 2 3
2 3 7
Sample Output
2HINT
1<=N<=500
根據乘法分配律可知,對於$b(i,j)$ ,只有$a[i],a[j]$ 都選才會有貢獻。
而選擇$a[j]$會導致選擇$-c[j]$.
可以發現這是個最大權閉合子圖的模型。
$S->b[i][j],b[i][j]->c[i],b[i][j]->c[j],c[i]->T$
代碼:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 300050 #define M 2000050 #define inf 100000000 int head[N],to[M],nxt[M],flow[M],cnt=1,sum,n; int dep[N],Q[N],l,r,S,T,idx[510][510],c[510]; inline void add(int u,int v,int f) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f; to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0; } bool bfs() { memset(dep,0,sizeof(dep)); l=r=0;Q[r++]=S;dep[S]=1; while(l<r) { int x=Q[l++],i; for(i=head[x];i;i=nxt[i]) { if(!dep[to[i]]&&flow[i]) { dep[to[i]]=dep[x]+1; if(to[i]==T) return 1; Q[r++]=to[i]; } } } return 0; } int dfs(int x,int mf) { if(x==T) return mf; int i,nf=0; for(i=head[x];i;i=nxt[i]) { if(dep[to[i]]==dep[x]+1&&flow[i]) { int tmp=dfs(to[i],min(mf-nf,flow[i])); if(!tmp) dep[to[i]]=0; nf+=tmp; flow[i]-=tmp; flow[i^1]+=tmp; if(nf==mf) break; } } return nf; } void dinic() { int f; while(bfs()) while(f=dfs(S,inf)) sum-=f; printf("%d\n",sum); } int main() { int i,j,x; scanf("%d",&n); S=n*n+n+1;T=S+1; int tot=0; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { idx[i][j]=++tot; scanf("%d",&x); sum+=x; add(S,tot,x); } } for(i=1;i<=n;i++) { scanf("%d",&c[i]); add(i+n*n,T,c[i]); } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { add(idx[i][j],n*n+i,inf); add(idx[i][j],n*n+j,inf); } } dinic(); }
BZOJ_3996_[TJOI2015]線性代數_最大權閉合子圖