[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. 消除ADB错误“more than one device and emulator”的方法(转)

    当我连着手机充电的时候,启动模拟器调试,执行ADB指令时,报错.C:\Users\gaojs>adb shellerror: more than one device and emulatorC ...

  2. 阿里云centos6.5实践编译安装LNMP架构web环境

    LNMP 代表的就是:Linux系统下Nginx+MySQL+PHP这种网站服务器架构. 本次测试需求: **实践centos6.5编译安装 LNMP生产环境 架构 web生产环境 使用 ngx_pa ...

  3. Linq in条件查询

    Linq 实现sql中的not in和in条件查询   T-SQL的IN: Select ProductID, ProductName, CategoryID From dbo.Products Wh ...

  4. LeetCode刷题第二天

    2.给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们 ...

  5. Java数据类型和不同数据类型在JVM内存分配

    1.java数据类型分类 Java语言是强类型(Strongly typed)语言,强类型包含两方面的含义:①所有的变量必须先声明,后使用:②指定类型的变量只能接受类型与之匹配的值.这意味着每个变量和 ...

  6. 小tip: base64:URL背景图片与web页面性能优化——张鑫旭

    一.base64百科 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,可用于在HTTP环境下传递较长的标识信息. 某人: 唉,我彻底废柴了,为何上面明明是中文,洒家却看不懂嘞,为什 ...

  7. new DialogInterface.OnClickListener()报错的解决办法

    在项目过程中 new DialogInterface.OnClickListener()总是报下面的错 Illegal qualified access from the type parameter ...

  8. curl 封装类

    <?php /** * author: zbseoag * QQ: 617937424 用法: $content = Curl::instance()->url($url)->get ...

  9. Vmware搭建LNMP环境(Centos7+Nginx+Mysql+PHP7.1.8)

    参考:1.Linux学习之CentOS(一)----在VMware虚拟机中安装CentOS 7(图文教程) 2.Centos7搭建LNMP环境 3.MySQL5.7修改默认root密码 4.CentO ...

  10. egg.js-基于koa2的node.js进阶(一)

    一.路由进阶Egg路由的路由重定向,路由分组 在router.js修改为如下格式require引用 module.exports = app => { const { router, contr ...