• [TJOI2015]线性代数


    题目

    还是挺不错的题,首先你得看出来这是一个网络流

    下面用(A_{i},C_{i})来简记(A_{1,i},C_{1,i})

    首先是(A imes B),得到一个(1 imes n),之后减掉矩阵(C),我们设得到的矩阵为(D)

    满足(D_j=sum_{k=1}^nA_k imes B_{k,j}-C_j)

    之后是(D imes A^T)

    结果是

    [sum_{j=1}^nA_jD_j=sum_{j=1}^nsum_{k=1}^nA_jA_k imes B_{k,j}-sum_{i=1}^nC_j ]

    我们要最大化这个柿子,同时(A)又是一个(0/1)矩阵,我们可以想到最小割

    如果(B_{j,k})能产生贡献的话,那么就要求(A_j=A_k=1),但是(A_j=A_k=1)却需要减掉(C_j,C_k)

    于是我们建立超级源汇,中间一排(n)个点,表示(A)

    超级源连中间的每一个点(i)一条边权为(C_i)的边,表示割掉这条边去和超级汇相连,即(A_i=1),需要减掉(C_i)

    对于一对点((i,j)),我们新建一个点(g)(g)向超级汇连边权为(B_{i,j})的边,(i,j)(g)连边权(inf)的边,这样只有在(i,j)同时和超级汇相连的时候才不用割掉这条边

    答案就是(sum_{i=1}^nsum_{j=1}^nB_{i,j}- ext{最小割})

    代码

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=505*505+505;
    const int inf=99999999;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct E{int v,nxt,f;}e[maxn*8];
    int head[maxn],d[maxn],cur[maxn],c[505],b[505][505];
    std::queue<int> q;
    int n,num=1,S,T,ans;
    inline void C(int x,int y,int f) {
    	e[++num].v=y;e[num].nxt=head[x];
    	e[num].f=f;head[x]=num;
    }
    inline void add(int x,int y,int f) {C(x,y,f),C(y,x,0);}
    inline int BFS() {
    	for(re int i=S;i<=T;i++) cur[i]=head[i],d[i]=0;
    	d[S]=1;q.push(S);
    	while(!q.empty()) {
    		int k=q.front();q.pop();
    		for(re int i=head[k];i;i=e[i].nxt)
    		if(!d[e[i].v]&&e[i].f) d[e[i].v]=d[k]+1,q.push(e[i].v);
    	}
    	return d[T];
    }
    int dfs(int x,int now) {
    	if(x==T||!now) return now;
    	int flow=0,ff;
    	for(re int& i=cur[x];i;i=e[i].nxt)
    	if(d[e[i].v]==d[x]+1) {
    		ff=dfs(e[i].v,min(now,e[i].f));
    		if(ff<=0) continue;
    		now-=ff,flow+=ff,e[i].f-=ff,e[i^1].f+=ff;
    		if(!now) break;
    	}
    	return flow;
    }
    int main() {
    	n=read();
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=n;j++) b[i][j]=read(),ans+=b[i][j];
    	for(re int i=1;i<=n;i++) c[i]=read();
    	T=n;for(re int i=1;i<=n;i++) add(S,i,c[i]);
    	int ed=T+1;
    	for(re int i=1;i<=n;i++) 
    		for(re int j=1;j<=n;j++) ed++;
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=n;j++) {
    			++T;
    			add(i,T,inf),add(j,T,inf);
    			add(T,ed,b[i][j]);
    		}
    	++T;
    	while(BFS()) ans-=dfs(S,inf);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    程序员修炼之道阅读笔记2
    程序员修炼之道阅读笔记1
    软件体系架构的质量属性
    计算贴现率相关问题
    以《淘宝网》为例,描绘质量属性的六个常见属性场景
    第十四周总结
    软件需求模式阅读笔记
    第十三周总结
    第十二周总结
    重大技术需求进度报告六
  • 原文地址:https://www.cnblogs.com/asuldb/p/10727480.html
Copyright © 2020-2023  润新知