[2018HN省队集训D5T1] 沼泽地marshland

题意

给定一张 \(n\times n\) 的棋盘, 对于位置 \((x,y)\), 若 \(x+y\) 为奇数则可能有一个正权值. 你可以在棋盘上互不重叠地任意放置最多 \(m\) 个L形三骨牌, 放置后骨牌拐角处的格子权值清零. 其中 \(k\) 个格子是障碍且障碍处权值必定为 \(0\). 最小化权值总和.

\(n\le 50\).

题解

这种乍一看像插头DP但是又让你求最优解而不是计数的棋盘题多半就是网络流了.

首先拐角的地方如果不是带权点的话这张骨牌没卵用, 所以我们只算拐角是带权点的骨牌. 容易发现覆盖一个带权点时必定会覆盖两个共顶点的无权点, 不难想到在无权点之间连权值为对应带权点的边然后跑最大权匹配.

无权点其实也组成了一个网格图(转 \(45^\circ\) 就看出来了), 所以可以黑白染色跑费用流. (实际上就是按奇偶行分类)

但是这样可能会出现重复计算某个带权点的贡献的情况. 所以我们必须要让包含同一个带权点的情况互斥. 只要加一对点在中间连一条容量为 \(1\) 权值为带权点的值的边, 然后再把它周围的点都用这对点收束到一起就好了.

或者说这是个三分图匹配?

建完图限制一下流量不超过 \(m\) 跑最小(大)费用流就好了. 用总和减去覆盖掉的权值.

参考代码

#include <bits/stdc++.h>

const int MAXN=110;
const int MAXV=1e4+10;
const int MAXE=3e5+10;
const int INFI=0x7F7F7F7F;
const int d[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; struct Edge{
int from;
int to;
int dis;
int flow;
Edge* rev;
Edge* next;
};
Edge E[MAXE];
Edge* head[MAXV];
Edge* top=E; int n;
int m;
int k;
int dis[MAXV];
bool vis[MAXV];
bool inq[MAXV];
int a[MAXN][MAXN];
int id[MAXN][MAXN];
int idx[MAXN][MAXN];
bool blk[MAXN][MAXN]; int Dinic(int,int);
bool SPFA(int,int);
int DFS(int,int,int);
void Insert(int,int,int,int); int main(){
scanf("%d%d%d",&n,&m,&k);
int sum=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",a[i]+j);
sum+=a[i][j];
}
}
for(int i=0;i<k;i++){
int x,y;
scanf("%d%d",&x,&y);
blk[x][y]=true;
}
int cnt=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
id[i][j]=++cnt;
if((i^j)&1)
idx[i][j]=++cnt;
}
}
int s=0,t=cnt+1,ss=cnt+2;
Insert(ss,s,0,m);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(!blk[i][j]){
if((i^j)&1){
Insert(id[i][j],idx[i][j],-a[i][j],1);
for(int k=0;k<4;k++){
std::pair<int,int> a(i+d[k][0],j+d[k][1]),b(i+d[(k+1)%4][0],j+d[(k+1)%4][1]);
if(id[a.first][a.second]&&id[b.first][b.second]){
if(a.first&1){
Insert(id[a.first][a.second],id[i][j],0,1);
Insert(idx[i][j],id[b.first][b.second],0,1);
}
else{
Insert(id[b.first][b.second],id[i][j],0,1);
Insert(idx[i][j],id[a.first][a.second],0,1);
}
}
}
}
else{
if(i&1)
Insert(s,id[i][j],0,1);
else
Insert(id[i][j],t,0,1);
}
}
}
}
printf("%d\n",sum+Dinic(ss,t));
return 0;
} int Dinic(int s,int t){
int ans=0;
while(SPFA(s,t))
ans+=dis[t]*DFS(s,INFI,t);
return ans;
} int DFS(int s,int flow,int t){
if(s==t||flow<=0)
return flow;
int rest=flow;
vis[s]=true;
for(Edge* i=head[s];i!=NULL;i=i->next){
if(i->flow>0&&dis[i->to]==dis[s]+i->dis&&!vis[i->to]){
int tmp=DFS(i->to,std::min(rest,i->flow),t);
rest-=tmp;
i->flow-=tmp;
i->rev->flow+=tmp;
}
}
return flow-rest;
} bool SPFA(int s,int t){
memset(dis,0x7F,sizeof(dis));
memset(vis,0,sizeof(vis));
std::queue<int> q;
q.push(s);
dis[s]=0;
vis[s]=true;
while(!q.empty()){
s=q.front();
q.pop();
vis[s]=false;
for(Edge* i=head[s];i!=NULL;i=i->next){
if(i->flow>0&&dis[i->to]>dis[s]+i->dis){
dis[i->to]=dis[s]+i->dis;
if(!vis[i->to]){
q.push(i->to);
vis[i->to]=true;
}
}
}
}
return dis[t]<0;
} inline void Insert(int from,int to,int dis,int flow){
top->from=from;
top->to=to;
top->dis=dis;
top->flow=flow;
top->rev=top+1;
top->next=head[from];
head[from]=top++; top->from=to;
top->to=from;
top->dis=-dis;
top->flow=0;
top->rev=top-1;
top->next=head[to];
head[to]=top++;
}

[2018HN省队集训D5T1] 沼泽地marshland的更多相关文章

  1. [2018HN省队集训D9T1] circle

    [2018HN省队集训D9T1] circle 题意 给定一个 \(n\) 个点的竞赛图并在其中钦定了 \(k\) 个点, 数据保证删去钦定的 \(k\) 个点后这个图没有环. 问在不删去钦定的这 \ ...

  2. [2018HN省队集训D8T1] 杀毒软件

    [2018HN省队集训D8T1] 杀毒软件 题意 给定一个 \(m\) 个01串的字典以及一个长度为 \(n\) 的 01? 序列. 对这个序列进行 \(q\) 次操作, 修改某个位置的字符情况以及查 ...

  3. [2018HN省队集训D8T3] 水果拼盘

    [2018HN省队集训D8T3] 水果拼盘 题意 给定 \(n\) 个集合, 每个集合包含 \([1,m]\) 中的一些整数, 在这些集合中随机选取 \(k\) 个集合, 求这 \(k\) 个集合的并 ...

  4. [2018HN省队集训D6T2] girls

    [2018HN省队集训D6T2] girls 题意 给定一张 \(n\) 个点 \(m\) 条边的无向图, 求选三个不同结点并使它们两两不邻接的所有方案的权值和 \(\bmod 2^{64}\) 的值 ...

  5. [Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform

    [Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform 题意 给定一个小写字母构成的字符串, 每个字符有一个非负权值. 输出所有满足权值和等于这个子串在所有本质 ...

  6. [2018HN省队集训D5T2] party

    [2018HN省队集训D5T2] party 题意 给定一棵 \(n\) 个点以 \(1\) 为根的有根树, 每个点有一个 \([1,m]\) 的权值. 有 \(q\) 个查询, 每次给定一个大小为 ...

  7. [Codeforces 321D][2018HN省队集训D4T2] Ciel and Flipboard

    [Codeforces 321D][2018HN省队集训D4T2] Ciel and Flipboard 题意 给定一个 \(n\times n\) 的矩阵 \(A\), (\(n\) 为奇数) , ...

  8. [2018HN省队集训D1T3] Or

    [2018HN省队集训D1T3] Or 题意 给定 \(n\) 和 \(k\), 求长度为 \(n\) 的满足下列条件的数列的数量模 \(998244353\) 的值: 所有值在 \([1,2^k)\ ...

  9. [2018HN省队集训D1T1] Tree

    [2018HN省队集训D1T1] Tree 题意 给定一棵带点权树, 要求支持下面三种操作: 1 root 将 root 设为根. 2 u v d 将以 \(\operatorname{LCA} (u ...

随机推荐

  1. PHP初级篇

    PHP初级篇 PHP环境搭建: 企业中常用到的环境是:Linux+Apache+MySQL+PHP 学习环境是:Windows+Apache+MySQL+PHP 工具 Apache 2.4.4 MyS ...

  2. oracle = : := 和变量绑定 oracle通配符和运算符

    这篇是7788凑的:":="是赋值语句 如: l_name :='sky';..."=" 是判断是否相等. 如: if 1=1 then...":&q ...

  3. ActiveMQ专题1: 入门实例

    序 好久没有写博客了,最近真的是可以说是忙成狗了.项目的事和自己的终身大事忙得焦头烂额,好在是一切都是越来越好了...... 趁着项目今天唯一的一点喘息时间,加上项目开始接触到的mq,开始写一篇amq ...

  4. JavaScript try...catch用法

    一.用法 try...catch语句用了处理代码中可能出现的错误信息,将要进行测试的代码块放在try中,如果代码出现异常,则会被catch捕获 其格式如下: <script> try{ / ...

  5. c#socket TCP同步网络通信

    一.socket简介 socket就是套接字,它是引用网络连接的特殊文件描述符,由三个基本要素组成: 1: AddressFamily(网络类型) 2: SocketType(数据传输类型) 3:Pr ...

  6. 【转】CSS浮动(float,clear)通俗讲解

    作者:杨元 本文链接:http://www.cnblogs.com/iyangyuan/archive/2013/03/27/2983813.html 很早以前就接触过CSS,但对于浮动始终非常迷惑, ...

  7. 关于Sqlite的一个demo

      直接上代码: class DBHelperSqlite { ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetC ...

  8. 未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序的解决方法

    在win7 操作系统中SQL2008导入excel2007 出现: 未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序 的解决方法: 出现这个原因是office 2007 ...

  9. Mybatis源码正确打开方式

    精心挑选要阅读的源码项目: 饮水思源——官方文档,先看文档再看源码: 下载源码,安装到本地,保证能编译运行: 从宏观到微观,从整体到细节: 找到入口,抓主放次,梳理核心流程: 源码调试,找到核心数据结 ...

  10. 零基础学python习题 - Python必须知道的基础语法

    1. 以下变量命名不正确的是(D) A. foo = the_value B. foo = l_value C. foo = _value D. foo = value_& 2. 计算2的38 ...