bzoj 2127 happiness【网络流dinic】

参考:https://www.cnblogs.com/chenyushuo/p/5144957.html 不得不说这个建图方法真是非常妙啊

假设S点选理,T点选文,a[i][j]为(i,j)选文收益,b[i][j]为(i,j)选理收益,c[i][j]为同时选文收益,d[i][j]为同时选文收益。

那么对于每个点x=(i+1)*m+j,我们连接

\[
c[s,x]=b[i][j]
\]

\[
c[x,t]=a[i][j]
\]

对于有利益相关的x,y两点,连接

\[
c[s,x]=d[i][j]/2
\]

\[
c[s,y]=d[i][j]/2
\]

\[
c[x,t]=c[i][j]/2
\]

\[
c[y,t]=c[i][j]/2
\]

\[
c[x,y]=c[i][j]/2+d[i][j]/2
\]

\[
c[y,x]=c[i][j]/2+d[i][j]/2
\]

建完的图:

然后考虑最小割,下面枚举几种情况:

都选文,即割掉了x选理,y选理和(x,y)都选理:

都选理,即割掉了x选文,y选文和(x,y)都选文:

x选文y选理,即割掉了x选理,y选文,(x,y)都选理/+(x,y)都选理/2+(x,y)都选文/2+(x,y)都选文/2,即,割掉x选理,y选文,(x,y)都选理,(x,y)都选文:

y选文x选理,即割掉了x选文,y选理,(x,y)都选理/+(x,y)都选理/2+(x,y)都选文/2+(x,y)都选文/2,即,割掉x选文,y选理,(x,y)都选理,(x,y)都选文:

对于除以2的操作,为避免下取整的误差,我们选择把所有流量都*2,最后再/2。

$ ans=sum(全部收益)- 最小割 $

p.s.用邻接表建图的时候先把每个点选单科的边连上,再练同时选的收益,否则会重

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=105,E=1000005,inf=1e9,P=500005;
int n,m,a[N][N],b[N][N],c[N][N],d[N][N],s,t,sum,cnt=1,h[P],le[N*N];
struct qwe
{
    int ne,to,va;
}e[E];
int read()
{
    int r=0;
    char p=getchar();
    while(p<‘0‘||p>‘9‘)
        p=getchar();
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r;
}
void add(int u,int v,int w)
{
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    e[cnt].va=w;
    h[u]=cnt;
}
bool bfs()
{
    queue<int>q;
    memset(le,0,sizeof(le));
    le[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();//cout<<u<<"AAAAAAAAAAAA"<<endl;
        q.pop();
        for(int i=h[u];i;i=e[i].ne)
            if(e[i].va&&!le[e[i].to])
            {
                le[e[i].to]=le[u]+1;
                q.push(e[i].to);
            }
    }
    // for(int i=0;i<=5;i++)
        // cout<<le[i]<<" ";
    return le[t];
 }
int dfs(int u,int f)
{//cout<<u<<" "<<f<<endl;
    if(u==t)
    {
        //cout<<"!!";
        return f;
    }
    int used=0;
    for(int i=h[u];i;i=e[i].ne)
    {
        //cout<<u<<" "<<e[i].to<<"   "<<e[i].va<<endl;;
        if(e[i].va>0&&le[e[i].to]==le[u]+1)
        {//cout<<"OK"<<endl;
            int w=dfs(e[i].to,min(f-used,e[i].va));
            e[i].va-=w;
            e[i^1].va+=w;
            used+=w;
            if(used==f)
                return f;
        }
    }
    if(!used)
        le[u]=-1;
    return used;
}
int dinic()
{
    int ans=0;
    while(bfs())
        ans+=dfs(s,inf);//,cout<<ans<<endl;
    return ans;
}
int main()
{
    n=read(),m=read();
    s=0,t=n*m+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=read(),sum+=a[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            b[i][j]=read(),sum+=b[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            int x=(i-1)*m+j;
            add(s,x,b[i][j]<<1);
            add(x,s,0);
            add(x,t,a[i][j]<<1);
            add(t,x,0);
        }
    for(int i=1;i<n;i++)
        for(int j=1;j<=m;j++)
            c[i][j]=read(),sum+=c[i][j];
    for(int i=1;i<n;i++)
        for(int j=1;j<=m;j++)
            d[i][j]=read(),sum+=d[i][j];
    for(int i=1;i<n;i++)
        for(int j=1;j<=m;j++)
        {
            int x=(i-1)*m+j,y=i*m+j;
            add(s,x,d[i][j]);
            add(x,s,0);
            add(s,y,d[i][j]);
            add(y,s,0);
            add(x,y,c[i][j]+d[i][j]);
            add(y,x,c[i][j]+d[i][j]);
            add(x,t,c[i][j]);
            add(t,x,0);
            add(y,t,c[i][j]);
            add(t,y,0);
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<m;j++)
            c[i][j]=read(),sum+=c[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<m;j++)
            d[i][j]=read(),sum+=d[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<m;j++)
        {
            int x=(i-1)*m+j,y=(i-1)*m+j+1;
            add(s,x,d[i][j]);
            add(x,s,0);
            add(s,y,d[i][j]);
            add(y,s,0);
            add(x,y,c[i][j]+d[i][j]);
            add(y,x,c[i][j]+d[i][j]);
            add(x,t,c[i][j]);
            add(t,x,0);
            add(y,t,c[i][j]);
            add(t,y,0);
        }
    printf("%d\n",sum-(dinic()>>1));
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/8133838.html

时间: 2024-10-10 03:07:02

bzoj 2127 happiness【网络流dinic】的相关文章

bzoj——2127: happiness

2127: happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 2570  Solved: 1242[Submit][Status][Discuss] Description 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值.作为计算机竞赛教练的scp大老

BZOJ 2127: happiness( 最小割 )

最小割.. S连每个人(容量:选择理科的愉悦):每个人连T(容量:选择理科的愉悦) . 对于每一组(x, y, w)x和y同选理增加的愉悦w,新建节点V,V连x(INF),V连y(INF), S连V(w) 对于每一组(x, y, w)x和y同选文增加的愉悦w,新建节点V,x连V(INF),y连V(INF), V连T(w) ------------------------------------------------------------------- #include<cstdio> #i

[BZOJ 2127] happiness 【最小割】

题目链接:BZOJ - 2127 题目分析 首先,每个人要么学文科,要么学理科,所以可以想到是一个最小割模型. 我们就确定一个人如果和 S 相连就是学文,如果和 T 相连就是学理. 那么我们再来确定建图.首先使用最小割,就是先加上所有可能获得的权值,再减去最小割(即不能获得的权值). 如果一个人学理,就要割掉与 S 相连的边,那么就是要割掉学文的收益.于是,对于每个点,从 S 向它连边,权值为它学文的收益. 同理,对于每个点,从它向 T 连边,权值为它学理的收益. 对于两个相邻的人,他们有同时学

bzoj 2127: happiness

1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define M 100009 5 #define inf 2139062143 6 using namespace std; 7 int n,m,a[102][102],b[102][102],c[102][102],tot,cnt=1,T,ans,head[M],d[M],q[2*M],next[10*M],u[10*M],v[10*M];

BZOJ 2127: happiness(最小割解决集合划分)

Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 2350  Solved: 1138[Submit][Status][Discuss] Description 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值.作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的

[BZOJ 2127]happiness(最小割)

Description 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值.作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大. Solution 和文理分科那道一样啊…1A #include<iostream> #include<cstdlib> #include<cstd

POJ 1273 Drainage Ditches (网络流Dinic模板)

Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage

[网络流dinic]日常翻新

之前的排版简直辣眼睛,重写一遍好了 模板题是草地排水poj1273 网络流的基础思想就是瞎基本搜 但是搜要搜得有技巧,有特色 最简单的搜,无限深搜直到终点 稍微改进一下,宽搜先标号然后按层搜 再改进一下,把某些确定不再使用的点剔除 要点在于建立反向边给自己一个反悔的机会,用^1找到反向边 #include <stdio.h> #include <queue> #include <algorithm> #include <string.h> using nam

hdu2732 Leapin&#39; Lizards (网络流dinic)

D - Leapin' Lizards Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description Your platoon of wandering lizards has entered a strange room in the labyrinth you are exploring. As you are looking around for hidden treasur