[BZOJ2127]happiness

Description

高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。

Input

第一行两个正整数n,m。接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值。第二个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择理科获得的喜悦值。第三个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择文科获得的额外喜悦值。第四个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择理科获得的额外喜悦值。第五个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择文科获得的额外喜悦值。第六个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择理科获得的额外喜悦值。

Output

输出一个整数,表示喜悦值总和的最大值

Sample Input

1 2
1 1
100 110
1
1000 

Sample Output

1210

Solution

二元组建图,2016集训队候选队论文题,详见《网络流的一些建图方法》但是网上好像找不到

对于每个人建一个点,然后类似于这样的连边:

其中\(x,y\)为相邻的两个点,\(s,t\)为源汇点,那么枚举每人选文还是理有\(4\)种情况,然后可以根据损失情况列出方程:(注意这里忽略了每人选文还是理的单独的贡献)

\[a+b=v_1\\c+d=v_2\\a+d+e=b+c+e=v_1+v_2 \]

解出来可得:

\[a=b=\frac{v_1}{2},c=d=\frac{v_2}{2},e=\frac{v_1+v_2}{2} \]

那么就可以得到建图了。

具体可以看代码的主函数部分,注意没有必要处理小数,直接整体乘2就好了。

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;
const int inf = 1e9;

int n,m,s,t,tot=1;
int head[maxn],vis[maxn],dis[maxn];
int l[102][102],r[102][102],a[102][102],b[102][102];
struct edge{int to,nxt,w;}e[maxn<<1];

void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
void ins(int u,int v,int w) {add(u,v,w),add(v,u,0);}
void ins2(int u,int v,int w) {ins(u,v,w),ins(v,u,w);}

int bfs() {
	memset(vis,0,(t+1)*10);
	memset(dis,63,(t+1)*10);
	queue<int > q;q.push(s);vis[s]=1;
	while(!q.empty()) {
		int now=q.front();q.pop();
		for(int i=head[now];i;i=e[i].nxt)
			if(!vis[e[i].to]&&e[i].w>0) {
				dis[e[i].to]=dis[now]+1;
				if(e[i].to==t) return 1;
				q.push(e[i].to),vis[e[i].to]=1;
			}
	}return 0;
}

int dfs(int x,int f) {
	if(x==t) return f;
	int used=0;
	for(int i=head[x];i;i=e[i].nxt)
		if(e[i].w>0&&dis[e[i].to]==dis[x]+1) {
			int d=dfs(e[i].to,min(f-used,e[i].w));
			if(d>0) e[i].w-=d,e[i^1].w+=d,used+=d;
			if(used==f) break;
		}dis[x]=-1;return used;
}

int dinic() {
	int flow=0;
	while(bfs()) flow+=dfs(s,inf);
	return flow;
}

int p(int x,int y) {return (x-1)*m+y;}

int main() {
	read(n),read(m);int ans=0;
	s=n*m+2,t=s+1;
	for(int i=1,x;i<=n;i++)
		for(int j=1;j<=m;j++) read(x),l[i][j]+=x<<1,ans+=x;
	for(int i=1,x;i<=n;i++)
		for(int j=1;j<=m;j++) read(x),r[i][j]+=x<<1,ans+=x;
	for(int i=1,x;i<=n-1;i++)
		for(int j=1;j<=m;j++)
			read(x),l[i][j]+=x,l[i+1][j]+=x,a[i][j]+=x,ans+=x;
	for(int i=1,x;i<=n-1;i++)
		for(int j=1;j<=m;j++)
			read(x),r[i][j]+=x,r[i+1][j]+=x,a[i][j]+=x,ans+=x;
	for(int i=1,x;i<=n;i++)
		for(int j=1;j<=m-1;j++)
			read(x),l[i][j]+=x,l[i][j+1]+=x,b[i][j]+=x,ans+=x;
	for(int i=1,x;i<=n;i++)
		for(int j=1;j<=m-1;j++)
			read(x),r[i][j]+=x,r[i][j+1]+=x,b[i][j]+=x,ans+=x;
	for(int i=1;i<=n-1;i++)
		for(int j=1;j<=m;j++) ins2(p(i,j),p(i+1,j),a[i][j]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m-1;j++) ins2(p(i,j),p(i,j+1),b[i][j]);
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ins(s,p(i,j),l[i][j]),ins(p(i,j),t,r[i][j]);
	write(ans-(dinic()>>1));
	return 0;
}
posted @ 2019-03-02 19:46  Hyscere  阅读(158)  评论(0编辑  收藏  举报