bzoj3774 最优选择

题目描述:

小N手上有一个N*M的方格图,控制某一个点要付出Aij的代价,然后某个点如果被控制了,或者他周围的所有点(上下左右)都被控制了,那么他就算是被选择了的。一个点如果被选择了,那么可以得到Bij的回报,现在请你帮小N选一个最优的方案,使得回报-代价尽可能大。

题解:

最开始以为是最大权闭合子图裸题,后来发现少了点什么……

一般的图是正权->负权,但是这道题是负权->正权。

于是考虑拆点+最小割。

先假设手里拿着有所有的价值,即$\sum(b)$

对于一个点有三种情况:

1.占领这个点,此时代价为$a$;

2.不占领这个点,但是上下左右的某一个格子被占领了,此时代价为$0$;

2.不占领这个点,而且上下左右都是空的,此时代价为$b$;

我们可以先将棋盘黑白染色,然后建图。

重点是怎么建图。

拆点,每个点拆出的$x,y$之间连一条容量为$b$的边,源点向黑点的$x$连容量为$a$的边,白点的$y$向汇点连一条容量为$a$的边。

黑$x$向附近的白$x$连容量为$inf$的边,$y$同理。

意思是强迫割掉$a$,$b$或相邻点的$a$。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 5500;
const int inf = 0x3f3f3f3f;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){c=c*10+ch-‘0‘;ch=getchar();}
    x = f*c;
}
int n,m,hed[N],cnt=-1,S=1,T,cur[N];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
bool check(int x,int y){return x>=1&&y>=1&&x<=n&&y<=m;}
int _id(int x,int y){return (x-1)*m+y;}
ll ans;
struct EG
{
    int to,nxt;
    ll w;
}e[20*N];
void ae(int f,int t,ll w)
{
    e[++cnt].to = t;
    e[cnt].nxt  = hed[f];
    e[cnt].w    = w;
    hed[f] = cnt;
}
void AE(int f,int t,ll w)
{
    ae(f,t,w);
    ae(t,f,0);
}
int dep[N];
bool vis[N];
bool bfs()
{
    memset(dep,0x3f,sizeof(dep));
    memcpy(cur,hed,sizeof(cur));
    queue<int>q;
    dep[1]=0,vis[1]=1;q.push(1);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        for(int j=hed[u];~j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(e[j].w&&dep[to]>dep[u]+1)
            {
                dep[to]=dep[u]+1;
                if(!vis[to])vis[to]=1,q.push(to);
            }
        }
        vis[u]=0;
    }
    return dep[T]!=inf;
}
ll dfs(int u,ll lim)
{
    if(u==T||!lim)return lim;
    ll fl=0,f;
    for(int j=cur[u];~j;j=e[j].nxt)
    {
        cur[u]=j;
        int to = e[j].to;
        if(dep[to]==dep[u]+1&&(f=dfs(to,min(lim,e[j].w))))
        {
            fl+=f,lim-=f;
            e[j].w-=f,e[j^1].w+=f;
            if(!lim)break;
        }
    }
    return fl;
}
ll dinic()
{
    ll ret=0;
    while(bfs())
        ret+=dfs(S,inf);
    return ret;
}
int main()
{
    read(n),read(m);
    if(n==1&&m==1)
    {
        int a,b;
        read(a),read(b);
        if(b>a)ans=b-a;
        printf("%lld\n",ans);
        return 0;
    }
    memset(hed,-1,sizeof(hed));
    for(int i=1;i<=n;i++)
        for(int a,j=1;j<=m;j++)
        {
            read(a);
            if((i+j)&1)AE(S,_id(i,j)<<1,a);
            else AE(_id(i,j)<<1|1,T,a);
        }
    for(int i=1;i<=n;i++)
        for(int b,j=1;j<=m;j++)
        {
            read(b);ans+=b;
            int u = _id(i,j);
            AE(u<<1,u<<1|1,b);
            if((i+j)&1)
            {
                for(int x,y,o=0;o<4;o++)
                {
                    x = dx[o]+i,y = dy[o]+j;
                    if(check(x,y))
                    {
                        int t = _id(x,y);
                        AE(u<<1,t<<1,inf);
                        AE(u<<1|1,t<<1|1,inf);
                    }
                }
            }
        }
    printf("%lld\n",ans-dinic());
    return 0;
}

原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10349107.html

时间: 2024-10-13 20:58:42

bzoj3774 最优选择的相关文章

【BZOJ3774】最优选择 最小割

[BZOJ3774]最优选择 Description 小N手上有一个N*M的方格图,控制某一个点要付出Aij的代价,然后某个点如果被控制了,或者他周围的所有点(上下左右)都被控制了,那么他就算是被选择了的.一个点如果被选择了,那么可以得到Bij的回报,现在请你帮小N选一个最优的方案,使得回报-代价尽可能大. Input 第一行两个正整数N,M表示方格图的长与宽. 接下来N行每行M个整数Aij表示控制的代价. 接下来N行每行M个整数Bij表示选择的回报. Output 一个整数,表示最大的回报-代

BZOJ 3774: 最优选择( 最小割 )

最小割...二分染色然后把颜色不同的点的源汇反过来..然后就可以做了. 某个点(x,y): S->Id(x,y)(回报), Id(x,y)->T(代价), Id(i,j)&&Id(相邻节点)->newId(i,j)(+oo), newId(i,j)->T(回报) 然后染色不同的点反过来就可以了. 初始时答案为2*∑回报, 这样每个点要么割掉1个回报,要么割掉2个回报, 要么割掉1回报+代价.都对应着每一种方案 ----------------------------

【bzoj3774】最优选择 网络流最小割

题目描述 小N手上有一个N*M的方格图,控制某一个点要付出Aij的代价,然后某个点如果被控制了,或者他周围的所有点(上下左右)都被控制了,那么他就算是被选择了的.一个点如果被选择了,那么可以得到Bij的回报,现在请你帮小N选一个最优的方案,使得回报-代价尽可能大. 输入 第一行两个正整数N,M表示方格图的长与宽. 接下来N行每行M个整数Aij表示控制的代价. 接下来N行每行M个整数Bij表示选择的回报. 输出 一个整数,表示最大的回报-代价(如果一个都不控制那么就是0). 样例输入 3 31 1

MySQL数据类型的最优选择

慎重选择数据类型很重要.为啥哩?可以提高性能.原理如下: ● 存储(内存.磁盘).从而节省I/O(检索相同数据情况下) ● 计算.进而减负CPU负载 数据类型总体可分三种:数字.字符和时期 ㈠ 数字 ① 分类 ② 为整数类型指定宽度没啥意义.硬说呢.大概也是为了显示字符的个数.人性化点 因为.对于存储和计算而言.INT(1)和INT(100)是相同的 ③ 对于浮点.建议只指定数据类型.而不要指定精度 ④ 对于定点.尽量只在对小数精确计算时才使用.如存储财务数据 但天朝某些财务软件在其数据库内使用

建站服务器的最优选择之Windows Or Linux

转载于:http://www.0553114.com/news/detail-702287.html 不管是个人建站,还是中小型企业建站,选择一款合适的主机是站长朋友们共同的心愿.主机是选择Windows还是Linux是首先考虑的因素. 俗话说“没有最好的,只有最合适的”这句话在选择主机时特别适合,网站编程可以有多重选择,因此对于主机的需求也不可能一枝独秀. 选择Windows主机还是Linux主机,主要还是要根据托管网站的实际需求来进行选择. 在国内,Windows在PC机操作系统中已经深入人

[BZOJ 3774] 最优选择 【最小割】

题目链接:BZOJ - 3774 题目分析 此题与“文理分科”那道题目有些类似.都是使用最小割来求解,先加上可能获得的权值,在减掉必须舍弃的权值(最小割). 文理分科是规定每个人和 S 连就是选文,和 T 连就是选理.然后如果一个人和相邻的人都全文就会获得一个权值,那么我们就为这个权值建一个点,让这个点与必须同时选文的5个人连 INF 边.这样只要这 5 个人中有一个人选了理,就必须舍弃这个权值了. 再回到这道题目,这道题获得权值的条件是这个点被控制或这个点相邻的 4 个点都被控制. 这个“或”

如何选择一家公司?

之前很多读者问我手里有几个 offer,不知道怎么选择,这部分人的比例还是挺多的,一直都想写一下来着,但是一直都没抽出时间,今天这个特别的日子,送给你们一个特别的福利,就教教你们如何选择一家靠谱的公司吧! 优先选团队而不是优先选公司 我们加入一家公司,不管这家公司的规模怎样,业务形态怎样,对你影响最深的大都是你所在的团队,团队氛围.团队成员这些都是会影响着你在公司的每一天,所以我个人认为选择一家公司最重要的其实是选择团队,那么怎么判断团队是否值得加入呢? 所在团队是否承担公司的核心业务 一家公司

ArrayList、HashTable、List、Dictionary的演化及如何选择使用

在C#中,数组由于是固定长度的,所以常常不能满足我们开发的需求. 由于这种限制不方便,所以出现了ArrayList. ArrayList.List<T> ArrayList是可变长数组,你可以将任意多的数据Add到ArrayList里面.其内部维护的数组,当长度不足时,会自动扩容为原来的两倍. 但是ArrayList也有一个缺点,就是存入ArrayList里面的数据都是Object类型的,所以如果将值类型存入和取出的时候会发生装箱.拆箱操作(就是值类型与引用类型之间的转换),这个会影响程序性能

贪心算法之活动选择问题

import java.util.ArrayList; import java.util.List; public class ActiveSelector { private int[] s= {0,1,3,0,5,3,5,6,8,8,2,12}; //a0 a1..a11活动开始时间数组 private int[] f = {0,4,5,6,7,9,9,10,11,12,14,16}; //a0 a1..a11活动结束时间数组 List<Activity> ls = new ArrayLi