zoukankan      html  css  js  c++  java
  • bzoj 2127 happiness(最小割)

    【题目链接】

        http://www.lydsy.com/JudgeOnline/problem.php?id=2127

    【题意】

        有n*m个学生,每个人可以选择学文学理,都会有相应的分值,而且相邻两个人如果选择相同还会产生联合分值,求最大分值。

    【思路】

        建立ST,首先由S连边(S,u,a)a代表学文的分数,连向T(u,T,b)b表示学理的分数,这样构造出了两个人独立的分数。

    然后考虑联合分数,对于相邻的两个点xy,看下图(盗个图:

     

      设xy都学文的分数为w1,都学理的分数为w2,则a=w1/2,b=w1/2,c=w2/2,d=w2/2,e=(w1+w2)/2,每一种割与其对应的亏损分数如下:

          a+b          -w1      都学理->w2

          c+d          -w2      都学文->w1

          a+d+e       -w1-w2     不同->   0

          c+d+e       -w1-w2    ...

      注意双向边e,我们是变成两条有向边加入网络,而又因为我们求最小割用的是最大流的算法,所以这条边可以看作是一条双向且权值为e的边。

      然后把权值*2,解决精度问题。

    【代码】

      1 #include<set>
      2 #include<cmath>
      3 #include<queue>
      4 #include<vector>
      5 #include<cstdio>
      6 #include<cstring>
      7 #include<iostream>
      8 #include<algorithm>
      9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
     10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
     11 using namespace std;
     12 
     13 typedef long long ll;
     14 const int N = 4e4+10;
     15 const int M = 1e2+10;
     16 const int inf = 1e9;
     17 
     18 ll read() {
     19     char c=getchar();
     20     ll f=1,x=0;
     21     while(!isdigit(c)) {
     22         if(c=='-') f=-1; c=getchar();
     23     }
     24     while(isdigit(c))
     25         x=x*10+c-'0',c=getchar();
     26     return x*f;
     27 }
     28 
     29 struct Edge {
     30     int u,v,cap,flow;
     31 };
     32 struct Dinic {
     33     int n,m,s,t;
     34     int d[N],cur[N],vis[N];
     35     vector<int> g[N];
     36     vector<Edge> es;
     37     queue<int> q;
     38     void init(int n) {
     39         this->n=n;
     40         es.clear();
     41         FOR(i,0,n) g[i].clear();
     42     }
     43     void AddEdge(int u,int v,int w) {
     44         es.push_back((Edge){u,v,w,0});
     45         es.push_back((Edge){v,u,0,0});
     46         m=es.size();
     47         g[u].push_back(m-2);
     48         g[v].push_back(m-1);
     49     }
     50     int bfs() {
     51         memset(vis,0,sizeof(vis));
     52         q.push(s); d[s]=0; vis[s]=1;
     53         while(!q.empty()) {
     54             int u=q.front(); q.pop();
     55             FOR(i,0,(int)g[u].size()-1) {
     56                 Edge& e=es[g[u][i]];
     57                 int v=e.v;
     58                 if(!vis[v]&&e.cap>e.flow) {
     59                     vis[v]=1;
     60                     d[v]=d[u]+1;
     61                     q.push(v);
     62                 }
     63             }
     64         }
     65         return vis[t];
     66     }
     67     int dfs(int u,int a) {
     68         if(u==t||!a) return a;
     69         int flow=0,f;
     70         for(int& i=cur[u];i<g[u].size();i++) {
     71             Edge& e=es[g[u][i]];
     72             int v=e.v;
     73             if(d[v]==d[u]+1&&(f=dfs(v,min(a,e.cap-e.flow)))>0) {
     74                 e.flow+=f; 
     75                 es[g[u][i]^1].flow-=f;
     76                 flow+=f; a-=f;
     77                 if(!a) break;
     78             }
     79         }
     80         return flow;
     81     }
     82     int MaxFlow(int s,int t) {
     83         this->s=s,this->t=t;
     84         int flow=0;
     85         while(bfs()) {
     86             memset(cur,0,sizeof(cur));
     87             flow+=dfs(s,inf);
     88         }
     89         return flow;
     90     }
     91 } dc;
     92 
     93 int n,m,ans,a[M][M],b[M][M],id[M][M];
     94 
     95 void addedge(int u,int v,int w)
     96 {
     97     dc.AddEdge(u,v,w); dc.AddEdge(v,u,w);
     98 }
     99 
    100 int main()
    101 {
    102     n=read(),m=read();
    103     dc.init(n*m+2);
    104     int S=0,T=n*m+1;
    105     FOR(i,1,n) FOR(j,1,m) {
    106         a[i][j]=read(); ans+=a[i][j];
    107         a[i][j]<<=1; id[i][j]=(i-1)*m+j;
    108     }
    109     FOR(i,1,n) FOR(j,1,m) {
    110         b[i][j]=read(); ans+=b[i][j];
    111         b[i][j]<<=1;
    112     }
    113     int x;
    114     FOR(i,1,n-1) FOR(j,1,m) {
    115         x=read(); a[i][j]+=x,a[i+1][j]+=x;
    116         ans+=x;
    117         addedge(id[i][j],id[i+1][j],x);
    118     }
    119     FOR(i,1,n-1) FOR(j,1,m) {
    120         x=read(); b[i][j]+=x,b[i+1][j]+=x;
    121         ans+=x;
    122         addedge(id[i][j],id[i+1][j],x);
    123     }
    124     FOR(i,1,n) FOR(j,1,m-1) {
    125         x=read(); a[i][j]+=x,a[i][j+1]+=x;
    126         ans+=x;
    127         addedge(id[i][j],id[i][j+1],x);
    128     }
    129     FOR(i,1,n) FOR(j,1,m-1) {
    130         x=read(); b[i][j]+=x,b[i][j+1]+=x;
    131         ans+=x;
    132         addedge(id[i][j],id[i][j+1],x);
    133     }
    134     FOR(i,1,n) FOR(j,1,m) {
    135         dc.AddEdge(S,id[i][j],a[i][j]);
    136         dc.AddEdge(id[i][j],T,b[i][j]);
    137     }
    138     printf("%d
    ",ans-(dc.MaxFlow(S,T)>>1));
    139     return 0;
    140 }
  • 相关阅读:
    微人事项目-mybatis-持久层
    通过外键连接多个表
    springioc
    Redis 消息中间件 ServiceStack.Redis 轻量级
    深度数据对接 链接服务器 数据传输
    sqlserver 抓取所有执行语句 SQL语句分析 死锁 抓取
    sqlserver 索引优化 CPU占用过高 执行分析 服务器检查
    sql server 远程备份 bak 删除
    冒泡排序
    多线程 异步 beginInvoke EndInvoke 使用
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5307046.html
Copyright © 2011-2022 走看看