bzoj 3894: 文理分科

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



终于看到这题了。
S往所有点连边,流量为选文的满意值。
所有点往T连边,流量为选理的满意值。
然后新建节点。表示所有选文或者所有选理的满意值
如下面所说即可。。
/*

对于每一个人多建立两个新点,分别表示以这个点为中心的五个点全部选择文科和理科。记这两个点为S1和S2。

S1->以这个点为中心的五个点 f:INF

一这个点为中心的五个点->S2 f:INF*/

by

http://blog.csdn.net/jiangyuze831/article/details/43968571

//我只是不知道该怎么表述


#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
struct line
{
	 int s,t;
	 int f;
     int next;
}a[4000001];
int head[100001];
int edge;
int p;
int q[400001],d[400001];
inline void add(int s,int t,int f)
{
     a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
     a[edge].f=f;
}
inline bool bfs()
{
     int l=0,r=0;
     memset(q,0,sizeof(q));
     r++;
     q[r]=0;
     memset(d,-1,sizeof(d));
     d[0]=0;
     int i,k;
     while(l<r)
     {
     	  l++;
          int k=q[l];
          for(i=head[k];i!=0;i=a[i].next)
          {
               if(a[i].f>0&&d[a[i].t]==-1)
               {
                    d[a[i].t]=d[k]+1;
                    r++;
                    q[r]=a[i].t;
               }
          }
     }
     if(d[p]>=0)
          return true;
     return false;
}
inline int dfs(int k,int s)
{
     if(k==p)
          return s;
     int t=s;
     int i;
     for(i=head[k];i!=0;i=a[i].next)
     {
          if(d[a[i].t]==d[k]+1&&a[i].f>0)
          {
               int xx=dfs(a[i].t,min(s,a[i].f));
               a[i].f-=xx;
               if(i%2==0)
                    a[i-1].f+=xx;
               else
                    a[i+1].f+=xx;
               s-=xx;
          }
     }
     return t-s;
}
inline int maxflow()
{
     int s=0;
     while(bfs())
          s+=dfs(0,2100000000);
     return s;
}
int main()
{
     int n,m;
     scanf("%d%d",&n,&m);
     int i,j;
     int sum=0;
     int x;
     for(i=1;i<=n;i++)
     {
          for(j=1;j<=m;j++)
          {
               scanf("%d",&x);
               sum+=x;
               edge++;
               add(0,(i-1)*m+j,x);
               edge++;
               add((i-1)*m+j,0,0);
          }
     }
     p=n*m*4;
     for(i=1;i<=n;i++)
     {
          for(j=1;j<=m;j++)
          {
               scanf("%d",&x);
               sum+=x;
               edge++;
               add((i-1)*m+j,p,x);
               edge++;
               add(p,(i-1)*m+j,0);
          }
     }
     int d=n*m;
     for(i=1;i<=n;i++)
     {
          for(j=1;j<=m;j++)
          {
               scanf("%d",&x);
               sum+=x;
               d++;
               edge++;
               add(0,d,x);
               edge++;
               add(d,0,0);
               
               edge++;
               add(d,(i-1)*m+j,2100000000);
               edge++;
               add((i-1)*m+j,d,0);
               
               if(j>1)
               {
                    edge++;
                    add(d,(i-1)*m+j-1,2100000000);
                    edge++;
                    add((i-1)*m+j-1,d,0);
               }
               
               if(j<m)
               {
			        edge++;
                    add(d,(i-1)*m+j+1,2100000000);
                    edge++;
                    add((i-1)*m+j+1,d,0);
               }
               
               if(i<n)
               {
                    edge++;
                    add(d,i*m+j,2100000000);
                    edge++;
                    add(i*m+j,d,0);
               }
               
               if(i>1)
               {
                    edge++;
                    add(d,(i-2)*m+j,2100000000);
                    edge++;
                    add((i-2)*m+j,d,0);
               }
          }
     }
     
     
     for(i=1;i<=n;i++)
     {
          for(j=1;j<=m;j++)
          {
               scanf("%d",&x);
               sum+=x;
               d++;
               edge++;
               add(d,p,x);
               edge++;
               add(p,d,0);
               
               edge++;
               add((i-1)*m+j,d,2100000000);
               edge++;
               add(d,(i-1)*m+j,0);
               
               if(j>1)
               {
                    edge++;
                    add((i-1)*m+j-1,d,2100000000);
                    edge++;
                    add(d,(i-1)*m+j-1,0);
               }
               
               if(j<m)
               {
			        edge++;
                    add((i-1)*m+j+1,d,2100000000);
                    edge++;
                    add(d,(i-1)*m+j+1,0);
               }
               
               if(i<n)
               {
                    edge++;
                    add(i*m+j,d,2100000000);
                    edge++;
                    add(d,i*m+j,0);
               }
               
               if(i>1)
               {
                    edge++;
                    add((i-2)*m+j,d,2100000000);
                    edge++;
                    add(d,(i-2)*m+j,0);
               }
          }
     }
     printf("%d\n",sum-maxflow());
     return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值