LOJ #2100. 「TJOI2015」线性代数

题目

a n s = max ( i = 1 n j = 1 n a [ i ] b [ i ] [ j ] a [ j ] i = 1 n c [ i ] a [ i ] ) ans=\max(\sum_{i=1}^n \sum_{j=1}^n a[i]*b[i][j]*a[j]-\sum_{i=1}^n c[i]*a[i])

a a 1 × n 1\times n 的01矩阵.

我们先把所有 b [ i ] [ j ] b[i][j] 选择,再考虑 a [ i ] = 0 / 1 a[i]=0/1 的影响.

由于以后不管怎样代价都会减少,所有我们要的操作就是最小化变化,由 n 500 n\le 500 可以猜测用最小割.

考虑两个点 ( x , y ) (x,y) ,我们令最后 S S 侧的点表示0,否则为1.然后建出这样的图:

则有:

{ a x + a y = b [ y ] [ y ] + b [ x ] [ x ] + b [ x ] [ y ] + b [ y ] [ x ] b x + b y = c [ x ] + c [ y ] a x + v + b y = b [ x ] [ x ] + b [ x ] [ y ] + b [ y ] [ y ] + c y a y + v + b x = b [ y ] [ y ] + b [ y ] [ x ] + b [ x ] [ x ] + c x \begin{cases} a_x+a_y=b[y][y]+b[x][x]+b[x][y]+b[y][x]\\b_x+b_y=c[x]+c[y]\\a_x+v+b_y=b[x][x]+b[x][y]+b[y][y]+c_y\\a_y+v+b_x=b[y][y]+b[y][x]+b[x][x]+c_x\end{cases}

解得: { v = b [ x ] [ y ] + b [ y ] [ x ] 2 b x = c [ x ] b y = c [ y ] a x = b [ x ] [ x ] + v a y = b [ y ] [ y ] + v \begin{cases} v=\dfrac{b[x][y]+b[y][x]} 2 \\b_x=c[x]\\b_y=c[y]\\a_x=b[x][x]+v\\a_y=b[y][y]+v\end{cases}

特别的,推广到多点的时候对于 a x , v = i = 1 n b [ x ] [ i ] + b [ i ] [ x ] 2 a_x,v=\sum_{i=1}^n \dfrac{b[x][i]+b[i][x]}2 .

然后跑最小割就求出了最小损失.

#include<bits/stdc++.h>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define fi first
#define se second
#define vi vector<int>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=510,M=N*N,size=1<<20,mod=998244353;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}

int n,s[N],b[N][N],ans,st,ed,d[N],q[N],l,r;
struct edge{int y,next,c;}a[M]; int len=1,last[N],cur[N];
void ins(int x,int y,int c) {a[++len]=(edge){y,last[x],c}; last[x]=len;}
void add(int x,int y,int c,int d) {ins(x,y,c); ins(y,x,d);}

bool bfs() {
	q[l=r=1]=st; memset(d+1,0,sizeof(int[ed])); d[st]=1;
	while(l<=r) {
		int x=q[l++];
		for(int k=last[x],y;k;k=a[k].next)
			if(!d[y=a[k].y]&&a[k].c) 
				{q[++r]=y; d[y]=d[x]+1;}
	}
	return d[ed];
}

int dfs(int x,int f) {
	if(x==ed) return f;
	int s=0,t;
	for(int &k=cur[x],y,z;k;k=a[k].next) {
		y=a[k].y; z=min(a[k].c,f-s);
		if(d[y]==d[x]+1&&z) {
			s+=t=dfs(y,z);
			a[k].c-=t; a[k^1].c+=t;
			if(s==f) return f;
		}
	}
	if(!s) d[x]=0;
	return s;
}

int main() {
	qr(n); st=0; ed=n+1;
	for(int i=1;i<=n;i++) 
		for(int j=1;j<=n;j++)
			qr(b[i][j]),ans+=b[i][j],s[i]+=b[i][j],s[j]+=b[i][j];
	for(int i=1,x;i<=n;i++) qr(x),add(i,ed,x*2,0);
	for(int i=1;i<=n;i++) {
		add(st,i,s[i],0);
		for(int j=i+1;j<=n;j++)
			add(i,j,b[i][j]+b[j][i],b[i][j]+b[j][i]);
	}
	int cnt=0;
	while(bfs())
		memcpy(cur,last,sizeof(int[ed+1])),cnt+=dfs(st,mod);
	pr2(ans-cnt/2);
	return 0;
}



nt=0;
while(bfs())
memcpy(cur,last,sizeof(int[ed+1])),cnt+=dfs(st,mod);
pr2(ans-cnt/2);
return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/106672835