• BZOJ3894 文理分科


    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相连,求最小割,每条路径必定割掉一条边。
    下面考虑相邻全选情况。相邻中有任意一人选文,就没有额外的理科加成。同理相邻任意一人选理,就没有额外的文科加成。根据这个可以这样建图,每个点再拆为P1,P2,如图:
    1,2,3,4为某个位置的相邻点。与P1相连,流量为inf,这样如果任意一个选文科(假设a[1]),即与S相连,必定会割掉Same_s这条边。因为选a[1],肯定没有s[1],要保持不连通,最小割肯定割Same_s,不会割inf。同理对于Same_a,也一样。任意一个选理科(假设s[3]),与T相连,肯定没有a[3],要保持不连通,最小割肯定割Same_a,不会割inf。
    这样建图满足了额外加成的控制。
    直接用总的满意度-最小割即可
     
    第一次知道拆点方法,P(i,j) = (i-1)*m+j,然后P1=P(i,j)+n*m  P2=P(i,j)+2*n*m
     
      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define P(i,j) (i-1)*m+j
      4 
      5 const int maxn=100010;
      6 const int maxm=400010;
      7 const int inf=0x3f3f3f3f;
      8 struct Edge{
      9     int to,next,cap,flow,cost;
     10 }edge[maxm];
     11 
     12 int tol;
     13 int head[maxn];
     14 int gap[maxn],dep[maxn],cur[maxn];
     15 int dir[][2]={0,0,1,0,-1,0,0,-1,0,1};
     16 void init() {
     17     tol=0;
     18     memset(head,-1,sizeof(head));
     19 }
     20 void addedge(int u,int v,int w,int rw=0) {
     21     edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0;
     22     edge[tol].next=head[u];head[u]=tol++;
     23     edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0;
     24     edge[tol].next=head[v];head[v]=tol++;
     25 }
     26 
     27 int Q[maxn];
     28 void bfs(int start,int end) {
     29     memset(dep,-1,sizeof(dep));
     30     memset(gap,0,sizeof(gap));
     31     gap[0]=1;
     32     int front=0,rear=0;
     33     dep[end]=0;
     34     Q[rear++]=end;
     35     while(front!=rear) {
     36         int u=Q[front++];
     37         for(int i=head[u];i!=-1;i=edge[i].next) {
     38             int v=edge[i].to;
     39             if(dep[v]!=-1) continue;
     40             Q[rear++]=v;
     41             dep[v]=dep[u]+1;
     42             gap[dep[v]]++;
     43         }
     44     }
     45 }
     46 
     47 int S[maxn];
     48 int sap(int start,int end,int n) {
     49     bfs(start,end);
     50     memcpy(cur,head,sizeof(head));
     51     int top=0;
     52     int u=start;
     53     int ans=0;
     54     while(dep[start]<n) {
     55         if(u==end) {
     56             int minn=inf;
     57             int inser;
     58             for(int i=0;i<top;i++) {
     59                 if(minn>edge[S[i]].cap-edge[S[i]].flow) {
     60                     minn=edge[S[i]].cap-edge[S[i]].flow;
     61                     inser=i;
     62                 }
     63             }
     64             for(int i=0;i<top;i++) {
     65                 edge[S[i]].flow+=minn;
     66                 edge[S[i]^1].flow-=minn;
     67             }
     68             ans+=minn;
     69             top=inser;
     70             u=edge[S[top]^1].to;
     71             continue;
     72         }
     73         bool flag=false;
     74         int v;
     75         for(int i=cur[u];i!=-1;i=edge[i].next) {
     76             v=edge[i].to;
     77             if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]) {
     78                 flag=true;
     79                 cur[u]=i;
     80                 break;
     81             }
     82         }
     83         if(flag) {
     84             S[top++]=cur[u];
     85             u=v;
     86             continue;
     87         }
     88         int minn=n;
     89         for(int i=head[u];i!=-1;i=edge[i].next) {
     90             if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<minn) {
     91                 minn=dep[edge[i].to];
     92                 cur[u]=i;
     93             }
     94         }
     95         gap[dep[u]]--;
     96         if(!gap[dep[u]]) return ans;
     97         dep[u]=minn+1;
     98         gap[dep[u]]++;
     99         if(u!=start) u=edge[S[--top]^1].to;
    100     }
    101     return ans;
    102 }
    103 
    104 int main() {
    105     int n,m,x,sum;
    106     while(~scanf("%d%d",&n,&m)) {
    107         init();
    108         sum=0;
    109         int S=0,T=3*n*m+1;
    110         for(int i=1;i<=n;i++) {
    111             for(int j=1;j<=m;j++) {
    112                 scanf("%d",&x);
    113                 sum+=x;
    114                 addedge(S,P(i,j),x);
    115             }
    116         }
    117         for(int i=1;i<=n;i++) {
    118             for(int j=1;j<=m;j++) {
    119                 scanf("%d",&x);
    120                 sum+=x;
    121                 addedge(P(i,j),T,x);
    122             }
    123         }
    124         for(int i=1;i<=n;i++) {
    125             for(int j=1;j<=m;j++) {
    126                 scanf("%d",&x);
    127                 sum+=x;
    128                 for(int k=0;k<5;k++) {
    129                     int newx=i+dir[k][0];
    130                     int newy=j+dir[k][1];
    131                     if(newx<1||newx>n||newy<1||newy>m) continue;
    132                     addedge(P(i,j)+2*n*m,P(newx,newy),inf);
    133                 }
    134                 addedge(S,P(i,j)+2*n*m,x);
    135             }
    136         }
    137         for(int i=1;i<=n;i++) {
    138             for(int j=1;j<=m;j++) {
    139                 scanf("%d",&x);
    140                 sum+=x;
    141                 for(int k=0;k<5;k++) {
    142                     int newx=i+dir[k][0];
    143                     int newy=j+dir[k][1];
    144                     if(newx<1||newx>n||newy<1||newy>m) continue;
    145                     addedge(P(newx,newy),P(i,j)+n*m,inf);
    146                 }
    147                 addedge(P(i,j)+n*m,T,x);
    148             }
    149         }
    150         printf("%d
    ",sum-sap(0,T,T+1));
    151     }
    152 }
     
  • 相关阅读:
    JAVA火星坐标系、百度坐标系、84坐标系相互转换工具类
    MySQL查看数据库连接数
    GmSSL制作国密算法自签证书和 HTTPS 配置
    mysql占用内存过多
    Redis 缓存穿透、击穿、雪崩
    Linux清理入侵痕迹
    helm v3
    docker常见的网络
    fuser、lsof的使用
    find命令-exec选项,find命令配合xargs
  • 原文地址:https://www.cnblogs.com/ACMerszl/p/10803661.html
Copyright © 2020-2023  润新知