Solution -「P4313」文理分科

cirnovsky /

link。

Pretty nice practice for the min-cut trick.

Starting out we eliminate the constraint that if five students in a edge-connected component alternatively choose exactly the same learning branch they get an extra contribution to the answer, and easily we can work it out with the following way to build a network and run a max-flow algorithm:

  • Connect the source with each student and set the capacities of arcs as the number of euphorias the student would get if he or she chooses Arts.
  • Connect each student with the sink and set capacities of arcs as the number of euphorias the student would get if he or she chooses Science.

Considering how to deal with the extra contributions, we simply shrink the four neighboring students and the student himself or herself into one point and connect the source with this taken the extra contributions (for choosing Arts) as the capacities. Additionally, connect the point with the four neighboring students taken ++\infty as the capacities. So do we process ones who choose Science.

Just as the picture via @jun头吉吉 goes.

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
template<typename Kap> struct Net {
	const int n;
	struct Arc {
		int to; size_t rev; Kap cap,flow;
	};
	vector<vector<Arc>> e;
	vector<int> iter,lev;
	queue<int,list<int>> q;
	Net(int n):n(n),e(n),iter(n),lev(n) {}
	void line(int one,int ano,Kap ca) {
		one--; ano--;
		assert(0<=one && one<n && 0<=ano && ano<n);
		e[one].push_back((Arc){ano,e[ano].size()+(one==ano),ca,0});
		e[ano].push_back((Arc){one,e[one].size()-1,0,0});
	}
	Kap dinitz(int s,int t) { return dinitz(s-1,t-1,numeric_limits<Kap>::max()); }
	bool Getlayer(int s,int t) {
		lev.assign(n,0); q.push(s); lev[s]=1;
		while(q.size()) {
			int now=q.front(); q.pop();
			for(int i=0; i<int(e[now].size()); ++i) {
				int y=e[now][i].to;
				if(!lev[y] && e[now][i].cap>e[now][i].flow)	lev[y]=lev[now]+1,q.push(y);
			}
		}
		return lev[t];
	}
	Kap Augment(int now,Kap up,int t) {
		if(now==t)	return up;
		Kap rlow=0;
		for(int& i=iter[now]; i<int(e[now].size()); ++i) {
			if(up==rlow)	break;
			int y=e[now][i].to;
			if(lev[y]==lev[now]+1 && e[now][i].cap>e[now][i].flow) {
				Kap f=Augment(y,min(up-rlow,e[now][i].cap-e[now][i].flow),t);
				e[now][i].flow+=f; e[y][e[now][i].rev].flow-=f; rlow+=f;
			}
		}
		if(up==rlow)	lev[now]=0;
		return rlow;
	}
	Kap dinitz(int s,int t,const Kap INF) {
		assert(0<=s && s<n && 0<=t && t<n);
		Kap res=0;
		while(Getlayer(s,t))	iter.assign(n,0),res+=Augment(s,INF,t);
		return res;
	}
};
int n,m,a[200][200],b[200][200],exta[200][200],extb[200][200],S,T,sum;
int valid(int x,int y) { return x>=1 && x<=n && y>=1 && y<=m; }
int getID(int x,int y) { return (x-1)*m+y; }
int artify(int x) { return x+n*m; }
int sciencify(int x) { return x+n*m*2; }
signed main() {
	scanf("%d %d",&n,&m);
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=m; ++j)	scanf("%d",&a[i][j]),sum+=a[i][j];
	}
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=m; ++j)	scanf("%d",&b[i][j]),sum+=b[i][j];
	}
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=m; ++j)	scanf("%d",&exta[i][j]),sum+=exta[i][j];
	}
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=m; ++j)	scanf("%d",&extb[i][j]),sum+=extb[i][j];
	}
	Net<int> net(n*m*3+2); S=n*m*3+1; T=n*m*3+2;
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=m; ++j) {
			net.line(S,getID(i,j),a[i][j]);
			net.line(getID(i,j),T,b[i][j]);
			net.line(S,artify(getID(i,j)),exta[i][j]);
			net.line(artify(getID(i,j)),getID(i,j),INF);
			net.line(getID(i,j),sciencify(getID(i,j)),INF);
			net.line(sciencify(getID(i,j)),T,extb[i][j]);
			if(valid(i+1,j)) {
				net.line(artify(getID(i,j)),getID(i+1,j),INF);
				net.line(getID(i+1,j),sciencify(getID(i,j)),INF);
			}
			if(valid(i,j+1)) {
				net.line(artify(getID(i,j)),getID(i,j+1),INF);
				net.line(getID(i,j+1),sciencify(getID(i,j)),INF);
			}
			if(valid(i-1,j)) {
				net.line(artify(getID(i,j)),getID(i-1,j),INF);
				net.line(getID(i-1,j),sciencify(getID(i,j)),INF);
			}
			if(valid(i,j-1)) {
				net.line(artify(getID(i,j)),getID(i,j-1),INF);
				net.line(getID(i,j-1),sciencify(getID(i,j)),INF);
			}
		}
	}
	printf("%d\n",sum-net.dinitz(S,T));
	return 0;
}