题目
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
Data Constraint
Hint
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于10%以内的数据,n,m<=4
对于30%以内的数据,n,m<=8
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数
题解
这是一道二元关系的题目
这一道题目要求的是最大值,所以我们不妨用所有值的和减去最小割
然后就列出一堆式子然后解方程
具体的就不说了
其中有一个比较坑的地方,就是其实是没有确定解的以为方程不够,但是我们考虑到比如x和S的连边和y选文选理没有关系,这样就可以解出来我们想要的那个解了
然后跑一波最大流就好了
贴代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=1e5+5;
int fi[maxn],ne[maxn*2],dui[maxn*2],dui1[maxn*2],qc[maxn];
int mt[maxn],a[105][105][8],p[105][105];
int h[maxn],de[10010];
int i,j,k,l,m,n,x,y,tot,ans,now,cp,c1,c2;
void add(int x,int y,int z){
if (fi[x]==0) fi[x]=++now; else ne[qc[x]]=++now;
dui[now]=y; dui1[now]=z; qc[x]=now;
}
bool bfs(){
memset(de,255,sizeof(de)); de[cp+1]=0;
i=1; j=0; h[1]=cp+1;
while (i>j){
x=h[++j]; k=fi[x];
while (k){
if (dui1[k] && de[dui[k]]==-1){
de[dui[k]]=de[x]+1; h[++i]=dui[k];
}
k=ne[k];
}
}
if (de[cp+2]==-1) return false; else return true;
}
int dinic(int x,int w){
int i=fi[x],p,now=0;
if (x==cp+2) return w;
while (i){
if (de[dui[i]]==de[x]+1 && dui1[i]>0){
p=dinic(dui[i],min(w-now,dui1[i]));
if (p){
dui1[i]-=p;
dui1[i xor 1]+=p;
now+=p;
}
}
i=ne[i];
}
return now;
}
int main(){
freopen("1919.in","r",stdin);
scanf("%d%d",&n,&m);
fo(i,1,n) fo(j,1,m) p[i][j]=++cp;
fo(i,1,n) fo(j,1,m) scanf("%d",&a[i][j][1]);
fo(i,1,n) fo(j,1,m) scanf("%d",&a[i][j][2]);
fo(i,1,n-1) fo(j,1,m) scanf("%d",&a[i][j][3]);
fo(i,1,n-1) fo(j,1,m) scanf("%d",&a[i][j][4]);
fo(i,1,n) fo(j,1,m-1) scanf("%d",&a[i][j][5]);
fo(i,1,n) fo(j,1,m-1) scanf("%d",&a[i][j][6]);
fo(k,1,6) fo(i,1,n) fo(j,1,m){
a[i][j][k]=a[i][j][k]*2;
tot=tot+a[i][j][k];
}
now=1;
fo(i,3,n) fo(j,2,m){
x=p[i][j]; c1=c2=0;
c1=a[i][j][4]+a[i][j][6]+a[i-1][j][4]+a[i][j-1][6];
c2=a[i][j][3]+a[i][j][5]+a[i-1][j][3]+a[i][j-1][5];
add(cp+1,x,(c2/2)+a[i][j][1]); add(x,cp+1,0);
add(x,cp+2,(c1/2)+a[i][j][2]); add(cp+2,x,0);
if (i!=n){
y=p[i+1][j]; c1=(a[i][j][3]+a[i][j][4])/2;
add(x,y,c1); add(y,x,c1);
}
if (j!=m){
y=p[i][j+1]; c1=(a[i][j][5]+a[i][j][6])/2;
add(x,y,c1); add(y,x,c1);
}
}
while (bfs()){
l=dinic(cp+1,6666666);
ans+=l;
}
printf("%d\n",(tot-ans)/2);
return 0;
}