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
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数
HINT
Source
思路
这题面真难看。
(from 《浅析一类最小割问题(pty)》)
代码
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
const int maxn=100;
const int maxk=10000;
const int maxm=1000000;
const int inf=0x3f3f3f3f;
int n,m;
struct network_flow
{
int pre[maxm+10],now[maxk+10],son[maxm+10],val[maxm+10],tot;
int d[maxk+10];
inline int clear()
{
memset(now,0,sizeof now);
tot=1;
return 0;
}
inline int ins(int a,int b,int c)
{
pre[++tot]=now[a];
now[a]=tot;
son[tot]=b;
val[tot]=c;
return 0;
}
inline int add(int a,int b,int c)
{
ins(a,b,c);
ins(b,a,0);
return 0;
}
inline int bfs()
{
std::queue<int> q;
q.push(0);
memset(d,-1,sizeof d);
d[0]=0;
while(!q.empty())
{
int u=q.front(),j=now[u];
q.pop();
while(j)
{
int v=son[j];
if(val[j]&&(d[v]==-1))
{
d[v]=d[u]+1;
q.push(v);
if(v==n*m+1)
{
return 1;
}
}
j=pre[j];
}
}
return 0;
}
inline int dfs(int u,int flow)
{
if(u==n*m+1)
{
return flow;
}
int res=flow,j=now[u];
while(j&&res)
{
int v=son[j];
if(val[j]&&(d[v]==d[u]+1))
{
int f=dfs(v,std::min(res,val[j]));
if(!f)
{
d[v]=-1;
}
val[j]-=f;
val[j^1]+=f;
res-=f;
}
j=pre[j];
}
return flow-res;
}
inline int dinic()
{
int ans=0;
while(bfs())
{
ans+=dfs(0,inf);
}
return ans;
}
};
network_flow w;
int s[maxn+10][maxn+10],t[maxn+10][maxn+10],ans;
int main()
{
scanf("%d%d",&n,&m);
w.clear();
for(register int i=1; i<=n; ++i)
{
for(register int j=1; j<=m; ++j)
{
scanf("%d",&t[i][j]);
w.ins(n*m+1,(i-1)*m+j,0);
w.ins((i-1)*m+j,n*m+1,t[i][j]<<1);
ans+=t[i][j];
}
}
for(register int i=1; i<=n; ++i)
{
for(register int j=1; j<=m; ++j)
{
scanf("%d",&s[i][j]);
w.ins((i-1)*m+j,0,0);
w.ins(0,(i-1)*m+j,s[i][j]<<1);
ans+=s[i][j];
}
}
for(register int i=1; i<n; ++i)
{
for(register int j=1; j<=m; ++j)
{
scanf("%d",&t[i][j]);
}
}
for(register int i=1; i<n; ++i)
{
for(register int j=1; j<=m; ++j)
{
scanf("%d",&s[i][j]);
}
}
for(register int i=1; i<n; ++i)
{
for(register int j=1; j<=m; ++j)
{
int a=(i-1)*m+j,b=i*m+j,to=n*m+1;
w.ins(0,a,s[i][j]);
w.ins(a,0,0);
w.ins(0,b,s[i][j]);
w.ins(b,0,0);
w.ins(a,to,t[i][j]);
w.ins(to,a,0);
w.ins(b,to,t[i][j]);
w.ins(to,b,0);
w.ins(a,b,s[i][j]+t[i][j]);
w.ins(b,a,s[i][j]+t[i][j]);
ans+=s[i][j]+t[i][j];
}
}
for(register int i=1; i<=n; ++i)
{
for(register int j=1; j<m; ++j)
{
scanf("%d",&t[i][j]);
}
}
for(register int i=1; i<=n; ++i)
{
for(register int j=1; j<m; ++j)
{
scanf("%d",&s[i][j]);
}
}
for(register int i=1; i<=n; ++i)
{
for(register int j=1; j<m; ++j)
{
int a=(i-1)*m+j,b=(i-1)*m+j+1,to=n*m+1;
w.ins(0,a,s[i][j]);
w.ins(a,0,0);
w.ins(0,b,s[i][j]);
w.ins(b,0,0);
w.ins(b,to,t[i][j]);
w.ins(to,b,0);
w.ins(a,to,t[i][j]);
w.ins(to,a,0);
w.ins(a,b,s[i][j]+t[i][j]);
w.ins(b,a,s[i][j]+t[i][j]);
ans+=s[i][j]+t[i][j];
}
}
printf("%d\n",ans-(w.dinic()>>1));
return 0;
}