Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 194 Solved: 122
[Submit][Status][Discuss]
Description
文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠
结过)
小P所在的班级要进行文理分科。他的班级可以用一个n*m的矩阵进行
描述,每个格子代表一个同学的座位。每位同学必须从文科和理科中选择
一科。同学们在选择科目的时候会获得一个满意值。满意值按如下的方式
得到:
1.如果第i行第秒J的同学选择了文科,则他将获得art[i][j]的满意值,如
果选择理科,将得到science[i][j]的满意值。
2.如果第i行第J列的同学选择了文科,并且他相邻(两个格子相邻当且
仅当它们拥有一条相同的边)的同学全部选择了文科,则他会更开
心,所以会增加same_art[i][j]的满意值。
3.如果第i行第j列的同学选择了理科,并且他相邻的同学全部选择了理
科,则增加same_science[i]j[]的满意值。
小P想知道,大家应该如何选择,才能使所有人的满意值之和最大。请
告诉他这个最大值。
Input
第一行为两个正整数:n,m
接下来n术m个整数,表示art[i][j];
接下来n术m个整数.表示science[i][j];
接下来n术m个整数,表示same_art[i][j];
Output
输出为一个整数,表示最大的满意值之和
Sample Input
3 4
13 2 4 13
7 13 8 12
18 17 0 5
8 13 15 4
11 3 8 11
11 18 6 5
1 2 3 4
4 2 3 2
3 1 0 4
3 2 3 2
0 2 2 1
0 2 4 4
Sample Output
152
HINT
样例说明
1表示选择文科,0表示选择理科,方案如下:
1 0 0 1
0 1 0 0
1 0 0 0
N,M<=100,读入数据均<=500
最小割。
对于这种两个中选一个求最优解的就想到最小割了。
先把答案赋值为所有读入数字之和。
每个人向源点连文科的边,向汇点连理科的边,割掉哪边表示不选哪科。
然后再对每个人分别建一个“文科点”和“理科点”。
源点连向“文科点”,“文科点”连向本人和周围的人( inf ),只要有一个人选了理科,这条路就联通了,需要割掉。
“理科点”同理。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#define M 50005
#define inf 0x3f3f3f3f
using namespace std;
int fx[10][5];
int tot,n,m,cur[M],h[M],d[M],v[M],s,t;
struct edge
{
int from,to,cap,flow,ne;
}E[M*10];
int C(int x,int y)
{
return (x-1)*m+y;
}
int ok(int x,int y)
{
if (x>0&&y>0&&x<=n&&y<=m) return 1;
return 0;
}
void Addedge(int from,int to,int cap)
{
E[++tot]=(edge){from,to,cap,0,h[from]};
h[from]=tot;
E[++tot]=(edge){to,from,0,0,h[to]};
h[to]=tot;
}
int bfs()
{
for (int i=s;i<=t;i++)
v[i]=0;
d[s]=0;
queue<int> q;
q.push(s),v[s]=1;
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=h[x];i;i=E[i].ne)
{
edge e=E[i];
if (!v[e.to]&&e.cap>e.flow)
{
q.push(e.to);
v[e.to]=1;
d[e.to]=d[x]+1;
}
}
}
return v[t];
}
int dfs(int x,int a)
{
if (x==t||!a) return a;
int flow=0;
for (int i=h[x];i;i=E[i].ne)
{
edge &e=E[i];
if (d[e.to]!=d[x]+1) continue;
int f=dfs(e.to,min(a,e.cap-e.flow));
if (f>0)
{
flow+=f;
a-=f;
e.flow+=f;
E[i^1].flow-=f;
if (!a) break;
}
}
return flow;
}
int dinic()
{
int flow=0;
while (bfs())
{
for (int i=s;i<=t;i++)
cur[i]=h[i];
flow+=dfs(s,inf);
}
return flow;
}
int main()
{
tot=1;
scanf("%d%d",&n,&m);
int tot=0;
s=0,t=n*m*3+1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
Addedge(s,C(i,j),x);
tot+=x;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
Addedge(C(i,j),t,x);
tot+=x;
}
fx[1][1]=fx[2][1]=0,fx[1][2]=1,fx[2][2]=-1;
fx[3][2]=fx[4][2]=0,fx[3][1]=1,fx[4][1]=-1;
fx[5][1]=fx[5][2]=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
tot+=x;
Addedge(s,n*m+C(i,j),x);
for (int k=1;k<=5;k++)
{
int nx=i+fx[k][1],ny=j+fx[k][2];
if (ok(nx,ny)) Addedge(n*m+C(i,j),C(nx,ny),inf);
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
tot+=x;
Addedge(2*n*m+C(i,j),t,x);
for (int k=1;k<=5;k++)
{
int nx=i+fx[k][1],ny=j+fx[k][2];
if (ok(nx,ny)) Addedge(C(nx,ny),2*n*m+C(i,j),inf);
}
}
cout<<tot-dinic()<<endl;
return 0;
}
一开始忘记向本人连边了。。