费用流好题

本题的建图很有意思

正常我们看到棋盘问题应该先对整个棋盘黑白染色构成一个二分图,然后再考虑建图的问题

但是本题题目中已经明确区分了不同的斜线,问题在于怎么保证一个"L"形

因此我们进一步分析:显然柱子应该放在有代价的位置,我们应该由这样的位置向上下左右连边,保证有两个就行

但是这样建图是有问题的,因为首先,难以保证选了两个位置,其次,上下/左右这种选两个的方式也是不合法的!

因此我们考虑进一步拆解这个图:我们把这个图分成三部分(请自动忽略坏点),一部分是产生代价的地方,一部分是行列号均为偶数的部分,一部分是行列号均为奇数的部分

然后我们这样建图:源点->二级源点->行列号均为偶数的部分->产生代价的部分->行列号均为奇数的部分->汇点

其中二级源点是为了限制流量不得大于$m$的

这样连边之后,就很好的保证了必须选两个且排除了选上下两个/左右两个的情况

中间的点需要拆点,拆出来两个点流量为1,费用给出

注意跑的是最大费用流,跑出来以后还要用总费用减去这个最大费用,同时我们并不需要让流量最大,因此如果费用为负直接跳出

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
const int inf=0x3f3f3f3f;
struct Edge
{
int nxt;
int to;
int val;
int pri;
}edge[5000005];
int lim[10005];
int to[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
bool vis[55][55];
bool used[10005];
int dis[10005];
int w[55][55];
int val[10005];
int head[10005];
int pre[10005],f[10005];
int tot=0,cnt=1;
int n,m,k;
int ans=0;
int st,ed,eed;
int idx(int x,int y)
{
return (x-1)*n+y;
}
int ide(int x)
{
return x&1?x+1:x-1;
}
bool check(int x,int y)
{
return x>0&&x<=n&&y>0&&y<=n&&!vis[x][y];
}
void add(int l,int r,int z,int v)
{
edge[cnt].nxt=head[l];
edge[cnt].to=r;
edge[cnt].val=z;
edge[cnt].pri=v;
head[l]=cnt++;
}
void dadd(int l,int r,int z,int v)
{
add(l,r,z,v),add(r,l,0,-v);
}
bool spfa()
{
memset(dis,-0x3f,sizeof(dis));
memset(pre,-1,sizeof(pre));
memset(f,0,sizeof(f));
dis[tot+1]=0;
used[tot+1]=1;
lim[tot+1]=inf;
queue <int> M;
M.push(tot+1);
while(!M.empty())
{
int u=M.front();
M.pop();
for(int i=head[u];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(edge[i].val&&dis[to]<dis[u]+edge[i].pri)
{
dis[to]=dis[u]+edge[i].pri;
lim[to]=min(lim[u],edge[i].val);
f[to]=u,pre[to]=i;
if(!used[to])M.push(to),used[to]=1;
}
}
used[u]=0;
}
return dis[tot+3]>0&&pre[tot+3]!=-1;
}
int EK()
{
int maxf=0,maxv=0;
while(spfa())
{
maxf+=lim[tot+3],maxv+=lim[tot+3]*dis[tot+3];
int temp=tot+3;
while(temp!=tot+1)
{
edge[pre[temp]].val-=lim[tot+3];
edge[ide(pre[temp])].val+=lim[tot+3];
temp=f[temp];
}
}
return maxv;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
tot=n*n*2;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&w[i][j]),ans+=w[i][j];
dadd(tot+1,tot+2,m,0);
for(int i=1;i<=k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
vis[x][y]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(vis[i][j])continue;
dadd((idx(i,j)<<1)-1,idx(i,j)<<1,1,w[i][j]);
if((i&1)&&(j&1))dadd(idx(i,j)<<1,tot+3,1,0);
else if(!(i&1)&&!(j&1))
{
dadd(tot+2,(idx(i,j)<<1)-1,1,0);
for(int t=0;t<4;t++)
{
int toi=i+to[t][0],toj=j+to[t][1];
if(!check(toi,toj))continue;
dadd(idx(i,j)<<1,(idx(toi,toj)<<1)-1,1,0);
}
}else
{
for(int t=0;t<4;t++)
{
int toi=i+to[t][0],toj=j+to[t][1];
if(!check(toi,toj)||!(toi&1)||!(toj&1))continue;
dadd(idx(i,j)<<1,(idx(toi,toj)<<1)-1,1,0);
}
}
}
}
printf("%d\n",ans-EK());
return 0;
}

luogu 4142的更多相关文章

  1. Luogu 魔法学院杯-第二弹(萌新的第一法blog)

    虽然有点久远  还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题  沉迷游戏,伤感情 #include <queue> ...

  2. luogu p1268 树的重量——构造,真正考验编程能力

    题目链接:http://www.luogu.org/problem/show?pid=1268#sub -------- 这道题费了我不少心思= =其实思路和标称毫无差别,但是由于不习惯ACM风格的题 ...

  3. [luogu P2170] 选学霸(并查集+dp)

    题目传送门:https://www.luogu.org/problem/show?pid=2170 题目描述 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一 ...

  4. [luogu P2647] 最大收益(贪心+dp)

    题目传送门:https://www.luogu.org/problem/show?pid=2647 题目描述 现在你面前有n个物品,编号分别为1,2,3,--,n.你可以在这当中任意选择任意多个物品. ...

  5. Luogu 考前模拟Round. 1

    A.情书 题目:http://www.luogu.org/problem/show?pid=2264 赛中:sb题,直接暴力匹配就行了,注意一下读入和最后一句话的分句 赛后:卧槽 怎么只有40 B.小 ...

  6. luogu P2580 于是他错误的点名开始了

    luogu  P2580 于是他错误的点名开始了 https://www.luogu.org/problem/show?pid=2580 题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 他会一边 ...

  7. CJOJ 1331 【HNOI2011】数学作业 / Luogu 3216 【HNOI2011】数学作业 / HYSBZ 2326 数学作业(递推,矩阵)

    CJOJ 1331 [HNOI2011]数学作业 / Luogu 3216 [HNOI2011]数学作业 / HYSBZ 2326 数学作业(递推,矩阵) Description 小 C 数学成绩优异 ...

  8. Luogu 1349 广义斐波那契数列(递推,矩阵,快速幂)

    Luogu 1349 广义斐波那契数列(递推,矩阵,快速幂) Description 广义的斐波那契数列是指形如\[A_n=p*a_{n-1}+q*a_{n-2}\]的数列.今给定数列的两系数p和q, ...

  9. Luogu 1962 斐波那契数列(矩阵,递推)

    Luogu 1962 斐波那契数列(矩阵,递推) Description 大家都知道,斐波那契数列是满足如下性质的一个数列: f(1) = 1 f(2) = 1 f(n) = f(n-1) + f(n ...

  10. CJOJ 2255 【NOIP2016】组合数问题 / Luogu 2822 组合数问题 (递推)

    CJOJ 2255 [NOIP2016]组合数问题 / Luogu 2822 组合数问题 (递推) Description 组合数\[C^m_n\]表示的是从n个物品中选出m个物品的方案数.举个例子, ...

随机推荐

  1. ASP.NET Core Filter如何支持依赖注入

    通过Filter来支持:分别有IResourceFilter AuthorizeFilter ActionFilter ExceptionFilter ResultFilter,Filter也被称为拦 ...

  2. vue3 门户网站搭建5-图标

    奈何 element 自带的图标太少,不够用,故打算使用 vite-plugin-svg-icons 组件来封装 svg-icon . ps: ui 框架选用的 element-ui,为了能跟 vue ...

  3. kubeadm安装

    目录: 环境准备 所有节点安装docker 部署K8s集群 部署Dashboard 安装Harbor私有仓库 安装 master(2C/4G,cpu核心数要求大于2) 192.168.63.100 d ...

  4. thunar文件管理器修改默认的关联的终端

    有时候在文件管理器的文件夹中打开终端操作很方便.目前好用的文件管理器基本和虚拟中终端基本上是各个桌面环境的配套产品. 比如xfce环境的thunar文件管理器如果想搭配lxde环境的lxtermina ...

  5. nginx,git,maven面试题

    1.简述一下什么是Nginx,它有什么优势和功能? Nginx是一个web服务器和方向代理服务器,用于HTTP.HTTPS.SMTP.POP3和IMAP协议.因 它的稳定性.丰富的功能集.示例配置文件 ...

  6. 从零搭建hadoop集群之mysql安装

    Linux RPM 方式安装 MySQL在 hadoop02机器上 1. 安装新版mysql前,需将系统自带的mariadb-lib卸载 [root@hadoop02 ~]# rpm -qa|grep ...

  7. 实现ViewPager一次滑动多页(保持居中)

    项目中开发日历功能,需求是可以连续滑动多页,有列表的流畅.又要保持当前页居中显示. 参考文献:  http://www.open-open.com/lib/view/open1435026935638 ...

  8. 微信小程序授权及检测访问当前页面需要去登录的操作

    1.小程序授权登录 这里我直接复制代码: login.js const app = getApp() Page({ data: { //判断小程序的API,回调,参数,组件等是否在当前版本可用. ca ...

  9. 20220408_转载_LaTex数学公式基本代码

    https://blog.csdn.net/ViatorSun/article/details/82826664 超详细 LaTex数学公式

  10. Xcode基础文件概念

    Xcode基础概念 Schema.Target.Project 和 Workspace 是组成一个 Xcode 工程最核心的单元,也是我们首先需要理解的部分. Target Target 是我们工程中 ...