OJ题号:
BZOJ3996
题目大意:
给定一个矩阵$B_{nn}$,矩阵$C_{1n}$,存在一个01矩阵$A_{1,n}$使得$d=(A imes B-c) imes A^mathsf{T}$最大,求$d$的最大值。
思路:
化简以后可以得到$d=displaystyle{sum_{i=1}^{n}sum_{j=1}^{n}}a_ia_jb_{ij}-displaystyle{sum_{i=1}^{n}}a_ic_i$。
由于$A$是一个01矩阵,因此我们可以将这题转化为“取物品”的问题。
已知有$n$个物品,取第$i$个有$c_i$的收益,若同时取$i$和$j$则有$c_i+c_j+b_{ij}$的收益,求最大收益。
我们先设置超级源汇$S$和$T$,然后对于所有的$(i,j)$,连一条从$S$到$(i,j)$的容量为$b_{ij}$的边,再分别连从$(i,j)$到$i$和$j$的容量为$infty$的边。
对于每一个$i$,连一条从$i$到$T$的容量为$c_i$的边。
然后求出最小割$f$,则$d=displaystyle{sum_{i=1}^nsum_{j=1}^n}b_{ij}-f$。
然后用Edmonds-Karp算法写了一遍发现TLE了,改成用Dinic加上当前弧优化就能AC了。
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 #include<cstring> 6 inline int getint() { 7 char ch; 8 while(!isdigit(ch=getchar())); 9 int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int inf=0x7fffffff; 14 const int E=1501000,V=250502; 15 int s,t; 16 struct Edge { 17 int from,to,remain; 18 }; 19 int sz=0; 20 Edge e[E]; 21 std::vector<int> g[V]; 22 inline void add_edge(const int u,const int v,const int w) { 23 e[sz]=(Edge){u,v,w}; 24 g[u].push_back(sz); 25 sz++; 26 } 27 int lev[V]; 28 inline void bfs() { 29 for(int i=1;i<=t;i++) lev[i]=inf; 30 lev[s]=0; 31 std::queue<int> q; 32 q.push(s); 33 while(!q.empty()) { 34 int x=q.front(); 35 q.pop(); 36 for(unsigned i=0;i<g[x].size();i++) { 37 Edge &y=e[g[x][i]]; 38 if(y.remain&&lev[y.to]==inf) { 39 lev[y.to]=lev[x]+1; 40 q.push(y.to); 41 } 42 } 43 } 44 } 45 unsigned cur[V]={0}; 46 int dfs(const int x,const int flow) { 47 if(x==t) return flow; 48 for(unsigned &i=cur[x];i<g[x].size();i++) { 49 Edge y=e[g[x][i]]; 50 if(y.remain&&lev[x]<lev[y.to]) { 51 int f=dfs(y.to,std::min(flow,y.remain)); 52 if(f) { 53 e[g[x][i]].remain-=f; 54 e[g[x][i]^1].remain+=f; 55 return f; 56 } 57 } 58 } 59 return 0; 60 } 61 inline int Dinic() { 62 int maxflow=0; 63 for(;;) { 64 bfs(); 65 if(lev[t]==inf) break; 66 while(int flow=dfs(s,inf)) { 67 maxflow+=flow; 68 } 69 } 70 return maxflow; 71 } 72 int main() { 73 int n=getint(); 74 s=0,t=n*(n+1)+1; 75 int ans=0; 76 for(int i=1;i<=n;i++) { 77 for(int j=1;j<=n;j++) { 78 int id=i*n+j; 79 int w=getint(); 80 ans+=w; 81 add_edge(s,id,w); 82 add_edge(id,s,0); 83 add_edge(id,i,inf); 84 add_edge(i,id,0); 85 add_edge(id,j,inf); 86 add_edge(j,id,0); 87 } 88 } 89 for(int i=1;i<=n;i++) { 90 add_edge(i,t,getint()); 91 add_edge(t,i,0); 92 } 93 printf("%d ",ans-Dinic()); 94 return 0; 95 }
Edmonds-Karp的TLE代码:
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 #include<cstring> 6 inline int getint() { 7 char ch; 8 while(!isdigit(ch=getchar())); 9 int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int inf=0x7fffffff; 14 const int E=1501000,V=250502; 15 int s,t; 16 struct Edge { 17 int from,to,remain; 18 }; 19 int sz=0; 20 Edge e[E]; 21 std::vector<int> g[V]; 22 inline void add_edge(const int u,const int v,const int w) { 23 e[sz]=(Edge){u,v,w}; 24 g[u].push_back(sz); 25 sz++; 26 } 27 int a[V],p[V]; 28 inline int Augment() { 29 memset(a,0,sizeof a); 30 a[s]=inf; 31 std::queue<int> q; 32 q.push(s); 33 while(!q.empty()) { 34 int x=q.front(); 35 q.pop(); 36 for(unsigned i=0;i<g[x].size();i++) { 37 Edge &y=e[g[x][i]]; 38 if(y.remain&&!a[y.to]) { 39 a[y.to]=std::min(a[x],y.remain); 40 p[y.to]=g[x][i]; 41 q.push(y.to); 42 } 43 } 44 if(a[t]) break; 45 } 46 return a[t]; 47 } 48 inline int EdmondsKarp() { 49 int maxflow=0; 50 while(int flow=Augment()) { 51 for(int i=t;i!=s;i=e[p[i]].from) { 52 e[p[i]].remain-=flow; 53 e[p[i]^1].remain+=flow; 54 } 55 maxflow+=flow; 56 } 57 return maxflow; 58 } 59 int main() { 60 int n=getint(); 61 s=0,t=n*(n+1)+1; 62 int ans=0; 63 for(int i=1;i<=n;i++) { 64 for(int j=1;j<=n;j++) { 65 int id=i*n+j; 66 int w=getint(); 67 ans+=w; 68 add_edge(s,id,w); 69 add_edge(id,s,0); 70 add_edge(id,i,inf); 71 add_edge(i,id,0); 72 add_edge(id,j,inf); 73 add_edge(j,id,0); 74 } 75 } 76 for(int i=1;i<=n;i++) { 77 add_edge(i,t,getint()); 78 add_edge(t,i,0); 79 } 80 printf("%d ",ans-EdmondsKarp()); 81 return 0; 82 }