zoukankan      html  css  js  c++  java
  • [最小割] 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->i的边表示i选文科(称i为文科节点)
    • 那么假如一个集合内的人都选文会获得一个满意度,建立一个新节点连到s流量为满意度,在新节点和每个理科节点连上一条流量为正无穷的边
    • 只要集合内的任意一点选文科则必须要割掉这条边
    • 理科同理

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <algorithm>
     5 #define inf 1000000000
     6 using namespace std;
     7 int ans,tot,n,m,T,cnt=1,Q[30005],head[30005],state[30005];
     8 int dx[5]={0,0,1,-1,0},dy[5]={1,-1,0,0,0};
     9 struct edge{ int to,from,v; }e[1000005];
    10 void insert(int x,int y,int v)
    11 {
    12     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].v=v;
    13     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt,e[cnt].v=0;
    14 }
    15 bool bfs()
    16 {
    17     int p=0,q=1;
    18     memset(state,-1,sizeof(state));
    19     state[0]=Q[0]=0;
    20     while (p!=q)
    21     {
    22         int u=Q[p]; p++;
    23         for (int i=head[u];i;i=e[i].from) if (e[i].v&&state[e[i].to]==-1) state[e[i].to]=state[u]+1,Q[q++]=e[i].to;
    24     }
    25     return state[T]!=-1;
    26 }
    27 int dfs(int x,int maxf)
    28 {
    29     if (x==T) return maxf;
    30     int f=0,r;
    31     for (int i=head[x];i;i=e[i].from)
    32         if (e[i].v&&state[e[i].to]==state[x]+1)
    33         {
    34             r=dfs(e[i].to,min(e[i].v,maxf-f)),e[i].v-=r,e[i^1].v+=r,f+=r;
    35             if (f==maxf) return f;
    36         }
    37     if (!f) state[x]=-1;
    38     return f;
    39 }
    40 int main()
    41 {
    42     scanf("%d%d",&n,&m),T=3*n*m+1;
    43     for (int i=1,x;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&x),insert(0,(i-1)*m+j,x),tot+=x;
    44     for (int i=1,x;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&x),insert((i-1)*m+j,T,x),tot+=x;
    45     for (int i=1,v;i<=n;i++)
    46         for (int j=1;j<=m;j++)
    47         {
    48             scanf("%d",&v),tot+=v;
    49             for (int k=0;k<5;k++)
    50             {
    51                 int x=dx[k]+i,y=dy[k]+j;
    52                 if (x>n||y>m||x<1||y<1) continue;
    53                 insert((i-1)*m+j+n*m,(x-1)*m+y,inf);
    54             }
    55             insert(0,(i-1)*m+j+n*m,v);
    56         }
    57     for (int i=1,v;i<=n;i++)
    58         for (int j=1;j<=m;j++)
    59         {
    60             scanf("%d",&v),tot+=v;
    61             for (int k=0;k<5;k++)
    62             {
    63                 int x=dx[k]+i,y=dy[k]+j;
    64                 if (x>n||y>m||x<1||y<1) continue;
    65                 insert((x-1)*m+y,(i-1)*m+j+2*n*m,inf);
    66             }
    67             insert((i-1)*m+j+2*n*m,T,v);
    68         }
    69     while (bfs()) ans+=dfs(0,inf);
    70     printf("%d",tot-ans);
    71 }
  • 相关阅读:
    centos 7 安装zabbix 4.0
    django Middleware
    初探paramiko
    python中的反射
    python异常处理
    双绞线
    简易的CMDB服务端
    4-初识Django Admin
    数据资产管理实践纲要
    matplotlib 散点图,为不同区域的点添加不同颜色
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11157172.html
Copyright © 2011-2022 走看看