【BZOJ3996】[TJOI2015]线性代数 最大权闭合图
【BZOJ3996】[TJOI2015]线性代数
Description
给出一个N*N的矩阵B和一个1*N的矩阵C。求出一个1*N的01矩阵A.使得
D=(A*B-C)*A^T最大。其中A^T为A的转置。输出D
Input
第一行输入一个整数N,接下来N行输入B矩阵,第i行第J个数字代表Bij.
接下来一行输入N个整数,代表矩阵C。矩阵B和矩阵C中每个数字都是不超过1000的非负整数。
Output
输出最大的D
Sample Input
3
1 2 1
3 1 0
1 2 3
2 3 7
1 2 1
3 1 0
1 2 3
2 3 7
Sample Output
2
HINT
1<=N<=500
题解:上面的那个式子我们用乘法分配律拆开,然后直观理解就是如果想要获得B中(i,j)的权值,A[i]和A[j]都必须是1,如果A[i]是1,那么就一定要付出C[i]的代价,这就变成了一个求最大权闭合图的问题,建图还是挺容易的吧?
#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; int to[3000010],next[3000010],val[3000010],d[300000],head[300000]; queue<int> q; int n,cnt,tot,m,ans,S,T; int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } int bfs() { int i,u; memset(d,0,sizeof(d)); while(!q.empty()) q.pop(); q.push(S),d[S]=1; while(!q.empty()) { u=q.front(),q.pop(); for(i=head[u];i!=-1;i=next[i]) { if(!d[to[i]]&&val[i]) { d[to[i]]=d[u]+1; if(to[i]==T) return 1; q.push(to[i]); } } } return 0; } int dfs(int x,int mf) { if(x==T) return mf; int i,temp=mf,k; for(i=head[x];i!=-1;i=next[i]) { if(d[to[i]]==d[x]+1&&val[i]) { k=dfs(to[i],min(temp,val[i])); if(!k) d[to[i]]=0; val[i]-=k,val[i^1]+=k,temp-=k; if(!temp) break; } } return mf-temp; } void add(int a,int b,int c) { to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++; to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++; } int main() { m=n=rd(),tot=0,S=0,T=n*n+n+1; int i,j,a; memset(head,-1,sizeof(head)); for(i=1;i<=n;i++) for(j=1;j<=n;j++) a=rd(),tot+=a,add(S,++m,a),add(m,i,1<<30),add(m,j,1<<30); for(i=1;i<=n;i++) add(i,T,rd()); while(bfs()) ans+=dfs(S,1<<30); printf("%d",tot-ans); return 0; }
| 欢迎来原网站坐坐! >原文链接<