●BZOJ 3996 [TJOI2015]线性代数

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=3996

题解:

好题啊。
(不太熟悉矩阵相关,所以按某些博主的模型转换来理解的)
首先,那个式子可以化简为
D(某个数)=A * B * A' - C * A' ( A'为 A的倒置矩阵)
因为 A 为 01 矩阵,
把其考虑为 N个物品选或不选,
C[i]对应为i物品的花费,
而B[i,j]对应为同时选了i,j两个物品后带来的价值。
所以结合A,B,C的意义,用简单的矩阵知识去理解那个式子,
可以知道,D求得便是最大收益。
那么就转化为了 一个经典的最小割问题。(建图类似于网络流24道之太空飞行计划问题):
建立超源S,超汇T;
S -> (i,j) : B[i][j]
(i,j) -> (i) : INF
(i,j) -> (j) : INF
(i) -> T  : C[i]
然后 ANS=sum(B)-最小割

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 505*505
#define INF 0x3f3f3f3f
using namespace std;
struct Edge{
	int to[MAXN*8],cap[MAXN*8],nxt[MAXN*8],head[MAXN*2],ent;
	void Init(){
		ent=2; memset(head,0,sizeof(head));
	}
	void Adde(int u,int v,int w){
		to[ent]=v; cap[ent]=w; nxt[ent]=head[u]; head[u]=ent++;
		to[ent]=u; cap[ent]=0; nxt[ent]=head[v]; head[v]=ent++;
	}
	int Next(int i,bool type){
		return type?head[i]:nxt[i];
	}
}E;
int cur[MAXN*2],d[MAXN*2];
int N,S,T,ANS;
int idx(int i,int j){
	return j?(i-1)*N+j:N*N+i;
}
bool bfs(){
	memset(d,0,sizeof(d));
	queue<int>q; d[S]=1; q.push(S);
	while(!q.empty()){
		int u=q.front(); q.pop();
		for(int i=E.Next(u,1);i;i=E.Next(i,0)){
			int v=E.to[i];
			if(d[v]||!E.cap[i]) continue;
			d[v]=d[u]+1; q.push(v);
		}
	}
	return d[T];
}
int dfs(int u,int reflow){
	if(u==T||!reflow) return reflow;
	int flowout=0,f;
	for(int &i=cur[u];i;i=E.Next(i,0)){
		int v=E.to[i];
		if(!E.cap[i]||d[v]!=d[u]+1) continue;
		f=dfs(v,min(reflow,E.cap[i]));
		flowout+=f; E.cap[i^1]+=f;
		reflow-=f;	E.cap[i]-=f;
		if(!reflow) break;
	}
	if(!flowout) d[u]=0;
	return flowout;
}
int dinic(){//求最小割 
	int flow=0;
	while(bfs()){
		memcpy(cur,E.head,sizeof(E.head));
		flow+=dfs(S,INF);
	}
	return flow;
}
int main()
{
	E.Init();
	scanf("%d",&N); S=N*N+N+1; T=S+1;
	for(int i=1,x;i<=N;i++)
		for(int j=1;j<=N;j++){
			scanf("%d",&x); ANS+=x;
			E.Adde(S,idx(i,j),x);
			E.Adde(idx(i,j),idx(i,0),INF);
			E.Adde(idx(i,j),idx(j,0),INF);
		}
	for(int i=1,x;i<=N;i++){
		scanf("%d",&x);
		E.Adde(idx(i,0),T,x);
	}
	ANS-=dinic();
	printf("%d",ANS);
	return 0;
}
 

原文地址:https://www.cnblogs.com/zj75211/p/7931195.html