Loj 6068. 「2017 山东一轮集训 Day4」棋盘
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」棋盘的更多相关文章
- [LOJ#6068]. 「2017 山东一轮集训 Day4」棋盘[费用流]
		题意 题目链接 分析 考虑每个棋子对对应的横向纵向的极大区间的影响:记之前这个区间中的点数为 \(x\) ,那么此次多配对的数量即 \(x\) . 考虑费用流,\(S\rightarrow 横向区间 ... 
- LOJ 6068「2017 山东一轮集训 Day4」棋盘
		题意 一个 \(n\times n\) 的棋盘上面有若干障碍物. 定义两个棋子可以互相攻击当且仅当这两个棋子的横坐标或纵坐标相等而且中间不能隔着障碍物.(可以隔棋子) 有 \(q\) 次询问,每次询问 ... 
- Loj #6069. 「2017 山东一轮集训 Day4」塔
		Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ... 
- loj6068. 「2017 山东一轮集训 Day4」棋盘 二分图,网络流
		loj6068. 「2017 山东一轮集训 Day4」棋盘 链接 https://loj.ac/problem/6068 思路 上来没头绪,后来套算法,套了个网络流 经典二分图 左边横,右边列 先重新 ... 
- 「2017 山东一轮集训 Day4」棋盘(费用流)
		棋盘模型 + 动态加边 #include<cstdio> #include<algorithm> #include<iostream> #include<cs ... 
- Loj #6073.「2017 山东一轮集训 Day5」距离
		Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ... 
- LOJ #6074. 「2017 山东一轮集训 Day6」子序列
		#6074. 「2017 山东一轮集训 Day6」子序列 链接 分析: 首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j. ... 
- loj #6077. 「2017 山东一轮集训 Day7」逆序对
		#6077. 「2017 山东一轮集训 Day7」逆序对 题目描述 给定 n,k n, kn,k,请求出长度为 n nn 的逆序对数恰好为 k kk 的排列的个数.答案对 109+7 10 ^ 9 ... 
- LOJ #6119. 「2017 山东二轮集训 Day7」国王
		Description 在某个神奇的大陆上,有一个国家,这片大陆的所有城市间的道路网可以看做是一棵树,每个城市要么是工业城市,要么是农业城市,这个国家的人认为一条路径是 exciting 的,当且仅当 ... 
随机推荐
- P9架构师讲解从单机至亿级流量大型网站系统架构的演进过程
			阶段一.单机构建网站 网站的初期,我们经常会在单机上跑我们所有的程序和软件.此时我们使用一个容器,如tomcat.jetty.jboos,然后直接使用JSP/servlet技术,或者使用一些开源的框架 ... 
- 将Y-m-d转换为Y年m月d日
			自己编写的,不能直接套用,理解后可自行变化: $var=explode(' ',$res['act_starting']); $var1=$var[0]; $time=explode ... 
- jQuery中$.ajax()方法参数解析
			本文实例为大家讲解了jQuery $.ajax()方法参数,供大家参考,具体内容如下 $.ajax({ url:'test.do', data:{id:123,name:'xiaoming'}, ty ... 
- nodejs+expressjs+ws实现了websocket即时通讯,服务器和客户端互相通信
			nodejs代码 // 导入WebSocket模块: const WebSocket = require('ws'); // 引用Server类: const WebSocketServer = We ... 
- 三星450R5J windows8.1系统重装小结
			本人一台三星450R5J,到今年也差不多五六年了.虽然颜值很高,但是用久了真的不行,毕竟是属于商务型笔记本,这里我就不晒配置了.  比较一下四五年前的三星与现在使用的华硕,三星看起来更鲜.  准 ... 
- iOS ----------怎么修改xcode默认打开方式
			很简单就能解决:选中文件,右键,显示简介,打开方式,选择8.2.然后打钩. 
- loadrunner 脚本录制-Action分类
			脚本录制-Action分类 by:授客 QQ:1033553122 Action分类 l . Vuser_init 2. Vuser_end 3. Action 在lr中用户的初始化操作应该存放在V ... 
- (办公)百度api的使用
			这个只是入门,详细的还得看官方的文档http://lbsyun.baidu.com/index.php?title=jspopular3.0/guide/helloworld 百度地图的“Hello, ... 
- Linux网卡聚合时,其中一个网卡有两种配置的解决方法
			先来看看: ficonfig 其中第一网卡是ssh使用: 第二个网卡是在Linux 最小化安装后IP的配置(手动获取静态IP地址)这个文章中配置过ip是192.168.1.2:在Linux重命名网卡名 ... 
- CentOS6.5内 MySQL5.7.19编译安装
			作为博主这样的Linux菜鸟,CentOS下最喜欢的就是yum安装.但有时候因为特殊情况(例如被墙等),某些软件可能没办法直接通过yum来安装,这时候我们可以使用编译安装或者直接二进制文件安装. 本博 ... 
