[BZOJ 2127]happiness(最小割)

Description

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

Solution

文理分科那道一样啊…1A

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
int n,m,s,t,ans=0;
int level[50005],head[50005],cnt=0;
struct Node
{
    int next,to,cap;
}Edges[500005];
int read()
{
    int x=0,f=1;char c=getchar();
    while(c<‘0‘||c>‘9‘){
        if(c==‘-‘)f=-1;c=getchar();
    }
    while(c>=‘0‘&&c<=‘9‘){
        x=x*10+c-‘0‘;c=getchar();
    }
    return x*f;
}
void addedge(int u,int v,int c)
{
    Edges[cnt].next=head[u];
    head[u]=cnt;
    Edges[cnt].to=v;
    Edges[cnt++].cap=c;
}
void insert(int u,int v,int c)
{
    addedge(u,v,c);
    addedge(v,u,0);
}
int pos(int x,int y){return (x-1)*m+y;}
queue<int>q;
bool bfs()
{
    memset(level,-1,sizeof(level));
    q.push(s);level[s]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(level[v]==-1&&Edges[i].cap)
            level[v]=level[u]+1,q.push(v);
        }
    }
    if(level[t]==-1)return false;
    return true;
}
int dfs(int u,int f)
{
    if(u==t)return f;
    int flow=0,d;
    for(int i=head[u];~i&&flow<f;i=Edges[i].next)
    {
        int v=Edges[i].to;
        if(level[v]==level[u]+1&&Edges[i].cap)
        {
            d=dfs(v,min(f-flow,Edges[i].cap));
            flow+=d;
            Edges[i].cap-=d;
            Edges[i^1].cap+=d;
        }
    }
    if(!flow)level[u]=-1;
    return flow;
}
int main()
{
    memset(head,-1,sizeof(head));
    n=read(),m=read();
    s=0,t=n*m+1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        int x=read();
        insert(s,pos(i,j),x);
        ans+=x;
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        int x=read();
        insert(pos(i,j),t,x);
        ans+=x;
    }
    int num=t+1;
    for(int i=1;i<=n-1;i++)
    for(int j=1;j<=m;j++)
    {
        int x=read();
        insert(s,num,x);
        insert(num,pos(i,j),INF);
        insert(num,pos(i+1,j),INF);
        ans+=x;
        num++;
    }
    for(int i=1;i<=n-1;i++)
    for(int j=1;j<=m;j++)
    {
        int x=read();
        insert(num,t,x);
        insert(pos(i,j),num,INF);
        insert(pos(i+1,j),num,INF);
        ans+=x;
        num++;
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m-1;j++)
    {
        int x=read();
        insert(s,num,x);
        insert(num,pos(i,j),INF);
        insert(num,pos(i,j+1),INF);
        ans+=x;
        num++;
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m-1;j++)
    {
        int x=read();
        insert(num,t,x);
        insert(pos(i,j),num,INF);
        insert(pos(i,j+1),num,INF);
        ans+=x;
        num++;
    }
    int d;
    while(bfs())
    {
        while(d=dfs(s,INF))
        ans-=d;
    }
    printf("%d\n",ans);
    return 0;
} 
时间: 2024-12-29 06:47:06

[BZOJ 2127]happiness(最小割)的相关文章

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(最小割解决集合划分)

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

[BZOJ 2127] happiness 【最小割】

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

BZOJ 2561: 最小生成树(最小割)

U,V能在最小(大)生成树上,当且仅当权值比它小(大)的边无法连通U,V. 两次最小割就OK了. --------------------------------------------------------------------- #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<que

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];

【BZOJ2127】happiness 最小割 自己YY出来的建图、

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42609669 其实我就是觉得原创的访问量比未授权盗版多有点不爽233... 那个一看就觉得不是费用流就是最小割. 想想就确定最小割了. 考虑到一个人,文理不可兼得,不妨先建点,然后向源点(文科),汇点(理科)连边,流量(也就是割)是对应喜悦值.(这里的想法是先建个差不多的,有漏洞再拆点啊,建辅助点啊什么的) 然后再考虑一对朋友之间的共文理喜悦值: 如果都选文,那么需要割掉双方都选理的喜悦

BZOJ 2229 ZJOI2011 最小割 最小割+分治 400AC达成&amp;&amp;2000Submission达成

题目大意:给定一个图,多次询问有多少个点对之间的最小割小于等于某个值 最小割分治- - 首先朴素的想法是做O(n^2)遍网络流 但是这样显然是过不去的 根据一些结论,最小割最多有n-1个,这n-1个最小割构成一个最小割树 别问我为什么- - 因此我们分治寻找这n-1个最小割 每层分治,先任选两个点作为源汇做一遍最小割 然后找出S集和T集,对所有S集的点和T集的点构成的点对用本次得到的最小割更新一遍 注意更新的是全部S集和全部T集,不只是本次分治内部的S集和T集 然后将本次分治的点分成S集和T集,

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]/

bzoj——2127: happiness

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