Loj 6068. 「2017 山东一轮集训 Day4」棋盘

题目描述

给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍。定义棋盘上两个位置 $ (x, y),(u, v) $ 能互相攻击当前仅当满足以下两个条件:

  • $ x = u $ 或 $ y = v $
  • 对于 $ (x, y) $ 与 $ (u, v) $ 之间的所有位置,均不是障碍。

现在有 $ q $ 个询问,每个询问给定 $ k_i $,要求从棋盘中选出 $ k_i $ 个空位置来放棋子,问最少互相能攻击到的棋子对数是多少?

输入格式

第一行一个整数 $ n $。

接下来输入一个 $ n \times n $ 的字符矩阵,一个位置若为 .,则表示这是一个空位置,若为 #,则为障碍。

第 $ n + 2 $ 行输入一个整数 $ q $ 代表询问个数。

接下来 $ q $ 行,每行一个整数 $ k $,代表要放的棋子个数。

样例

样例输入

4
..#.
####
..#.
..#.
1
7

样例输出

2

数据范围与提示

对于 $ 20% $ 的数据,$ n \leq 5 $;

对于 $ 40% $ 的数据,$ n \leq 10 $;

另外有 $ 20% $ 的数据,$ q = 1 $;

对于 $ 100% $ 的数据,$ n \leq 50; q \leq 10000; k \leq $ 棋盘中空位置数量。

感觉对这种棋盘类的题不太熟啊!

这种棋盘上填棋子的题大概率是网络流之类的东西。

棋盘建图的一般套路就是:将每个行连通块和列连通块拿出来,分别于源点和汇点连边,对于每个\((x,y)\),有该点所在的行连通块向列连通块连边,流量为\(1\),表示这个位置可以放一个棋子。

然后这道题同一行/列可以放多个棋子,于是源点到某一个连通块连多条边。边权为差分值\(\frac{i\cdot(i+1)}{2}-\frac{i\cdot (i-1)}{2}=i\)。然后发现他的增量是单调递增的,所以直接费用流不会出问题。汇点同理。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 55 using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} int n;
char mp[N][N];
int S,T;
struct road {
int to,next;
int flow,c;
}s[1200010];
int h[N*N],cnt=1; void add(int i,int j,int f,int c) {
// cout<<"fr="<<i<<" to="<<j<<" flow="<<f<<" cost="<<c<<"\n";
s[++cnt]=(road) {j,h[i],f,c};h[i]=cnt;
s[++cnt]=(road) {i,h[j],0,-c};h[j]=cnt;
} int tot;
int hbel[N][N],lbel[N][N];
int res; bool vis[N*N];
queue<int>q;
int dis[N*N];
int ans[N*N],now;
int fr[N*N],e[N*N];
bool in[N*N];
int mx; bool spfa() {
memset(dis,0x3f,sizeof(dis));
dis[0]=0;
q.push(S);
while(!q.empty()) {
int v=q.front();q.pop();
in[v]=0;
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(s[i].flow&&dis[to]>dis[v]+s[i].c) {
dis[to]=dis[v]+s[i].c;
fr[to]=v;
e[to]=i;
if(!in[to]) in[to]=1,q.push(to);
}
}
}
if(dis[T]>1e9) return 0;
for(int i=T;i;i=fr[i]) {
s[e[i]].flow--;
s[e[i]^1].flow++;
}
now++;
ans[now]=ans[now-1]+dis[T];
if(now==mx) return 0;
return 1;
}
vector<int>que;
int size[N*N];
int main() {
n=Get();
for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
if(mp[i][j]=='#') continue ;
res++;
if(mp[i][j-1]!='.') hbel[i][j]=++tot;
else hbel[i][j]=hbel[i][j-1];
}
}
for(int j=1;j<=n;j++) {
for(int i=1;i<=n;i++) {
if(mp[i][j]=='#') continue ;
if(mp[i-1][j]!='.') lbel[i][j]=++tot;
else lbel[i][j]=lbel[i-1][j];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
size[hbel[i][j]]++,size[lbel[i][j]]++;
S=0,T=tot+1;
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
if(mp[i][j]!='.') continue ;
if(hbel[i][j]!=hbel[i][j-1]) {
for(int q=1;q<=size[hbel[i][j]];q++) add(S,hbel[i][j],1,q-1);
}
if(lbel[i][j]!=lbel[i-1][j]) {
for(int q=1;q<=size[lbel[i][j]];q++) add(lbel[i][j],T,1,q-1);
}
add(hbel[i][j],lbel[i][j],1,0);
}
} int Q=Get();
for(int i=0;i<Q;i++) {
int a=Get();
mx=max(mx,a);
que.push_back(a);
}
while(spfa());
for(int i=0;i<Q;i++) cout<<ans[que[i]]<<"\n";
return 0;
}

Loj 6068. 「2017 山东一轮集训 Day4」棋盘的更多相关文章

  1. [LOJ#6068]. 「2017 山东一轮集训 Day4」棋盘[费用流]

    题意 题目链接 分析 考虑每个棋子对对应的横向纵向的极大区间的影响:记之前这个区间中的点数为 \(x\) ,那么此次多配对的数量即 \(x\) . 考虑费用流,\(S\rightarrow 横向区间 ...

  2. LOJ 6068「2017 山东一轮集训 Day4」棋盘

    题意 一个 \(n\times n\) 的棋盘上面有若干障碍物. 定义两个棋子可以互相攻击当且仅当这两个棋子的横坐标或纵坐标相等而且中间不能隔着障碍物.(可以隔棋子) 有 \(q\) 次询问,每次询问 ...

  3. Loj #6069. 「2017 山东一轮集训 Day4」塔

    Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...

  4. loj6068. 「2017 山东一轮集训 Day4」棋盘 二分图,网络流

    loj6068. 「2017 山东一轮集训 Day4」棋盘 链接 https://loj.ac/problem/6068 思路 上来没头绪,后来套算法,套了个网络流 经典二分图 左边横,右边列 先重新 ...

  5. 「2017 山东一轮集训 Day4」棋盘(费用流)

    棋盘模型 + 动态加边 #include<cstdio> #include<algorithm> #include<iostream> #include<cs ...

  6. Loj #6073.「2017 山东一轮集训 Day5」距离

    Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ...

  7. LOJ #6074. 「2017 山东一轮集训 Day6」子序列

    #6074. 「2017 山东一轮集训 Day6」子序列 链接 分析: 首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j. ...

  8. loj #6077. 「2017 山东一轮集训 Day7」逆序对

    #6077. 「2017 山东一轮集训 Day7」逆序对   题目描述 给定 n,k n, kn,k,请求出长度为 n nn 的逆序对数恰好为 k kk 的排列的个数.答案对 109+7 10 ^ 9 ...

  9. LOJ #6119. 「2017 山东二轮集训 Day7」国王

    Description 在某个神奇的大陆上,有一个国家,这片大陆的所有城市间的道路网可以看做是一棵树,每个城市要么是工业城市,要么是农业城市,这个国家的人认为一条路径是 exciting 的,当且仅当 ...

随机推荐

  1. UWP: 妙用自定义 Action 以简化并重用代码

    相信每一位 App 开发者,在开发过程中,都会有一些代码被反复用到,比如:复制文本,打电话,发短信,发邮件,给应用添加评论等等.在项目之间复制这些代码段,实在不是一个好办法,所以大家可能会把这些代码放 ...

  2. 46.Linux-分析rc红外遥控平台驱动框架,修改内核的NEC解码函数BUG(1)

    内核版本          :  Linux 3.10.14 rc红外接收类型:  GPIO 类型的NEC红外编码 本章内容 1) rc体系结构分析 2) 分析红外platform_driver平台驱 ...

  3. mybatis_01简介

    1.1 MyBatis MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名 ...

  4. python使用tcp实现一个简单的下载器

    上一篇中介绍了tcp的流程,本篇通过写一个简单的文件下载器程序来巩固之前学的知识. 文件下载器的流程如下: 客户端: 输入目标服务器的ip和port 输入要下载文件的名称 从服务器下载文件保存到本地 ...

  5. Flask 系列之 FlaskForm

    通过使用 FlaskForm ,可以方便快捷的实现表单处理. 说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验 ...

  6. endpoint 异常

    原文地址:http://blog.csdn.net/ltylove2007/article/details/6128333 其他信息: 无法加载协定为“ServiceReference1.WebSer ...

  7. Html中的img标签 加载失败

    在Http请求时,有时会遇到img图片标签加载失败,不显示的情况: 解决方法,在重新给src属性赋值时,先将onerror事件清除掉,再赋值,这样就不会存在循环调用问题了,代码如下; <img ...

  8. iPhone手机怎么投屏到电脑上

    如今生活水平不断上升,人们更加追求高质量.高享受的生活,所以可以利用一切资源提高生活质量,享受更好的生活体验,比如说手机投屏电脑就可以提高我们的视觉体验,所以更多的人去尝试,那么iPhone手机怎么投 ...

  9. git 入门教程之协同开发

    前面我们已经介绍过远程仓库的相关概念,不过那时并没有深入探讨,只是讲解了如何创建远程仓库以及推送最新工作成果到远程仓库,实际上远程仓库对于团队协同开发很重要,不仅仅是团队协同开发的基础,也是代码备份的 ...

  10. 在Win32程序中嵌入Edge浏览器组件

    代码未经测试,只做个记录 据说只是改了UA. 在注册表修改这个路径,并且把自己程序添加进去,写一个浏览器控件的版本号,只要高于12000就自动改为Edge. For 64bit application ...