1. 程式人生 > >BZOJ3996 TJOI2015線性代數

BZOJ3996 TJOI2015線性代數

oid sin dash for std .org num 連通 bzoj3

先把矩陣式子化簡

原式=i=1nj=1nA[i]B[i][j]A[j]i=1nA[i]C[i]

因此我們發現問題轉化為選取一個點所獲收益是B[i][j],代價是C[i][j]

這是一個最小割問題。

先把答案記做所有b的和。

將邊按照s——>p[i][j](b[i][j]) p[i][j]——>i p[i][j]——>j i——>t(c[i])這樣建圖後我們刪去的那個最小割意義就是花費最少的使得整個圖不連通的量

如果刪在左邊就意味著這件物品我們不要了,如果刪去右邊的話就說明這件物品我們要付錢。

By:大奕哥

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1000005,inf=1e9;
 4 int head[N],cnt=-1,n,b[505][505],c[505];
 5 struct node{
 6     int to,nex,w;
 7 }e[4000005];
 8 void add(int x,int y,int w)
 9 {
10     e[++cnt].to=y;e[cnt].nex=head[x];head[x]=cnt;e[cnt].w=w;
11 e[++cnt].to=x;e[cnt].nex=head[y];head[y]=cnt;e[cnt].w=0; 12 } 13 int d[N],v[N],s,t; 14 queue<int>q; 15 bool bfs() 16 { 17 memset(v,0,sizeof(v)); 18 memset(d,-1,sizeof(d)); 19 d[s]=0;q.push(s); 20 while(!q.empty()) 21 { 22 int x=q.front();q.pop();v[x]=1
; 23 for(int i=head[x];i!=-1;i=e[i].nex) 24 { 25 int y=e[i].to; 26 if(d[y]!=-1||!e[i].w)continue; 27 d[y]=d[x]+1; 28 if(!v[y]){ 29 q.push(y);v[y]=1; 30 } 31 } 32 } 33 return d[t]!=-1; 34 } 35 int dfs(int x,int w,int yy) 36 { 37 if(!w||x==yy)return w; 38 int s=0; 39 for(int i=head[x];i!=-1;i=e[i].nex) 40 { 41 int y=e[i].to; 42 if(d[y]!=d[x]+1||!e[i].w)continue; 43 int flow=dfs(y,min(e[i].w,w-s),yy); 44 if(!flow)d[y]=-1; 45 e[i].w-=flow;e[i^1].w+=flow;s+=flow; 46 if(s==w)return s; 47 } 48 return s; 49 } 50 int main() 51 { 52 scanf("%d",&n);int sum=0,num=0; 53 memset(head,-1,sizeof(head)); 54 for(int i=1;i<=n;++i) 55 for(int j=1;j<=n;++j) 56 { 57 scanf("%d",&b[i][j]); 58 } 59 t=n*n+n+10; 60 for(int i=1;i<=n;++i) 61 scanf("%d",&c[i]),add(i+n*n,t,c[i]); 62 for(int i=1;i<=n;++i) 63 for(int j=1;j<=n;++j) 64 { 65 sum+=b[i][j]; 66 add(s,++num,b[i][j]); 67 add(num,i+n*n,inf); 68 add(num,j+n*n,inf); 69 } 70 while(bfs()){ 71 sum-=dfs(s,1e9,t); 72 } 73 printf("%d\n",sum); 74 return 0; 75 }

BZOJ3996 TJOI2015線性代數