zoukankan      html  css  js  c++  java
  • 【BZOJ2127】happiness 最小割

    题目大意:有一个$n imes m$的矩阵,矩阵的每个位置上有一个同学,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。求一个方案,使得全班的喜悦值总和最大。

    数据范围:$n,m≤100$,权值$≤5000$。
    此题直接最小割,对于一对相邻的同学$(A,B)$,设$L_A$表示$A$同学选理的喜悦值,$W_A$表示$A$同学选文的喜悦值(前面说的两种情况$B$同理),设$L$为两个人都选理的额外收获喜悦值,$W$为两个人都选文的额外收获喜悦值,则有:
    $S->A$ ,权值为:$L_A+frac{1}{2}L$
    $A->T$ ,权值为:$W_A+frac{1}{2}W$
    $S->A$ ,权值为:$L_A+frac{1}{2}L$
    $A->T$ ,权值为:$W_A+frac{1}{2}W$
    $A<->B$,权值为:$frac{1}{2}(L+W)$
    当点数变多的时候,情况会有所不同,基于这个思路简单变形下就好了
    建完图后跑最大流就行了
    B站上的数据比较水,我们OJ上的数据加强了必须加上一个特殊的剪枝才能过(新姿势get)

     1 #include<bits/stdc++.h>
     2 #define M 300005
     3 #define N 105
     4 #define INF 1145141919
     5 #define F(_x,_y) for(int i=1;i<=(_x);i++) for(int j=1;j<=(_y);j++) 
     6 using namespace std;
     7 
     8 struct edge{int u,v,next;}e[M]={0}; int head[M]={0},use=0;
     9 void add(int x,int y,int z){e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use++;}
    10 void Add(int x,int y,int z){add(x,y,z); add(y,x,0);}
    11 int n,m,a[N][N]={0},b[N][N]={0},sum=0,id[N][N]={0},d[N][N]={0},r[N][N]={0},cnt=0;
    12 int S,T,vis[M]={0}; queue<int> q;
    13 
    14 bool bfs(){
    15     q.push(S); memset(vis,0,(cnt+1)<<2); vis[S]=1;
    16     while(!q.empty()){
    17         int u=q.front(); q.pop();
    18         for(int i=head[u];~i;i=e[i].next)
    19         if(e[i].v&&vis[e[i].u]==0){
    20             vis[e[i].u]=vis[u]+1;
    21             q.push(e[i].u);
    22         }
    23     }
    24     return vis[T];
    25 }
    26 int dfs(int x,int flow){
    27     if(x==T) return flow; int sum=0;
    28     for(int i=head[x];~i;i=e[i].next) 
    29     if(e[i].v&&vis[e[i].u]==vis[x]+1){
    30         int k=dfs(e[i].u,min(flow,e[i].v));
    31         e[i].v-=k; e[i^1].v+=k;
    32         sum+=k; flow-=k;
    33         if(flow==0) return sum;
    34     }
    35     if(sum==0) vis[x]=-1;
    36     return sum;
    37 }
    38 int dinic(){
    39     int res=0;
    40     while(bfs()) 
    41     res+=dfs(S,INF);
    42     return res;
    43 }
    44 
    45 int main(){
    46     //freopen("in.txt","r",stdin);
    47     memset(head,-1,sizeof(head));
    48     S=0; T=1; cnt=1;
    49     scanf("%d%d",&n,&m);
    50     F(n,m) id[i][j]=++cnt;
    51     F(n,m) scanf("%d",&a[i][j]),sum+=a[i][j],a[i][j]<<=1;
    52     F(n,m) scanf("%d",&b[i][j]),sum+=b[i][j],b[i][j]<<=1;
    53     F(n-1,m){
    54         int x; scanf("%d",&x); 
    55         a[i][j]+=x; a[i+1][j]+=x; sum+=x; d[i][j]+=x;
    56     }
    57     F(n-1,m){
    58         int x; scanf("%d",&x); 
    59         b[i][j]+=x; b[i+1][j]+=x; sum+=x; d[i][j]+=x;
    60     }
    61     F(n,m-1){
    62         int x; scanf("%d",&x); 
    63         a[i][j]+=x; a[i][j+1]+=x; sum+=x; r[i][j]+=x;
    64     }
    65     F(n,m-1){
    66         int x; scanf("%d",&x); 
    67         b[i][j]+=x; b[i][j+1]+=x; sum+=x; r[i][j]+=x;
    68     }
    69     F(n,m){
    70         Add(S,id[i][j],a[i][j]);
    71         Add(id[i][j],T,b[i][j]);
    72     }
    73     F(n,m-1){
    74         add(id[i][j],id[i][j+1],r[i][j]);
    75         add(id[i][j+1],id[i][j],r[i][j]);
    76     }
    77     F(n-1,m){
    78         add(id[i][j],id[i+1][j],d[i][j]);
    79         add(id[i+1][j],id[i][j],d[i][j]);
    80     }
    81     int hh=dinic();
    82     hh>>=1;
    83     cout<<sum-hh<<endl;
    84 }

     

  • 相关阅读:
    hdu4122
    poj3410单调队列(单调栈)
    hdu3415 单调队列模板题
    网站指纹识别工具Whatweb的使用
    Python中shodan模块的使用
    Shodan的使用
    Google Hacking的用法
    PyCharm调试程序
    Python脚本与Metasploit交互进行自动永恒之蓝攻击
    关于PHP动态的接收传递的GET,POST和COOKIE变量
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10380628.html
Copyright © 2011-2022 走看看