【BZOJ 3894】 文理分科

3894: 文理分科

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

最小割。

对于这种两个中选一个求最优解的就想到最小割了。

先把答案赋值为所有读入数字之和。

每个人向源点连文科的边,向汇点连理科的边,割掉哪边表示不选哪科。

然后再对每个人分别建一个“文科点”和“理科点”。

源点连向“文科点”,“文科点”连向本人和周围的人(),只要有一个人选了理科,这条路就联通了,需要割掉。

“理科点”同理。

;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;}

一开始忘记向本人连边了。。

空虚无聊的时候就读书,但一定得有自己的生活目标和计划。

【BZOJ 3894】 文理分科

相关文章:

你感兴趣的文章:

标签云: