题意:有一个未知的边权为$1$的图,给定所有点到$1$的最短路$a_i$和到$2$的最短路$b_i$,问是否存在这样的图,如果存在,问图中最少有多少条边

先考虑$a_i$,有$a_1=0,a_i\neq0(i\neq1)$,对于一条边$(x,y)$有$|a_x-a_y|\leq1$,对于任意$x\neq1$,存在$(x,y)$使得$a_x-1=a_y$,对$b_i$也有类似的约束

所以,我们将点$i$作为$(a_i,b_i)$画在平面上,那么至少要有两条边:第一条连到$(a_i-1,b_i-1)$或$(a_i-1,b_i)$或$(a_i-1,b_i+1)$,第二条连到$(a_i-1,b_i-1)$或$(a_i,b_i-1)$或$(a_i+1,b_i-1)$,如果这时找不到可以连边的点,那么就无解了(点$1$不用连第一种边,点$2$不用连第二种边)

如果可以连,那么我们构造出了一个有$2n-2$条边的图,显然这个图是满足条件的

但我们要最小化图中边数,所以考虑寻找尽可能多的可以共用的边

以下我们将第一种边称为$a$边,第二种边称为$b$边,共用边只可能是两种情况:1.对于点$i$,存在$(a_i-1,b_i-1)$,此时$i$的$a$边和$b$边可以共用;2.存在$i,j$使得$a_i-1=a_j,b_i+1=b_j$,此时$i$的$a$边可以和$j$的$b$边共用

我们把这$2n-2$条边看成点,如果两条边可以共用,在代表它们的点之间连一条边,求最大匹配即可,虽然是一般图,但注意到只有那些满足$a_i+b_i$相等的点$i$引出的边才可能共用,所以建出来的图是这样的(图来自官方题解)

图中框代表某个坐标$(a_i,b_i)$上的点,红点代表$b$边,蓝点代表$a$边,如果方框内有连边说明存在$(a_i-1,b_i-1)$

这种分层图可以从左上往右下贪心选边求最大匹配,实现时只需维护每个坐标的未匹配点个数即可

总时间复杂度为$O(n\log n)$,感觉这题还是不错的

#include<stdio.h>
#include<map>
using namespace std;
map<int,map<int,int> >mp,vis;
int a[100010],b[100010];
bool ex(int x,int y){
	return mp.count(x)&&mp[x].count(y);
}
int main(){
	int n,i,j,s,las,now;
	scanf("%d",&n);
	#define wa {puts("-1");return 0;}
	for(i=1;i<=n;i++){
		scanf("%d%d",a+i,b+i);
		if(i!=1&&a[i]==0)wa
		if(i!=2&&b[i]==0)wa
		mp[a[i]][b[i]]++;
	}
	for(i=1;i<=n;i++){
		if(i!=2){
			if(!(ex(a[i]-1,b[i]-1)||ex(a[i],b[i]-1)||ex(a[i]+1,b[i]-1)))wa
		}
		if(i!=1){
			if(!(ex(a[i]-1,b[i]+1)||ex(a[i]-1,b[i])||ex(a[i]-1,b[i]-1)))wa
		}
	}
	s=0;
	for(i=1;i<=n;i++){
		if(!ex(a[i]-1,b[i]+1)&&!vis[a[i]][b[i]]){
			vis[a[i]][b[i]]=1;
			las=0;
			for(j=0;ex(a[i]+j,b[i]-j);j++){
				now=mp[a[i]+j][b[i]-j];
				s+=min(las,now);
				now-=min(las,now);
				if(ex(a[i]+j-1,b[i]-j-1)){
					s+=now;
					now=min(las,mp[a[i]+j][b[i]-j]);
				}else
					now=mp[a[i]+j][b[i]-j];
				las=now;
			}
		}
	}
	printf("%d",2*n-2-s);
}

[CODE FESTIVAL 2016]Distance Pairs的更多相关文章

  1. 【AtCoder】CODE FESTIVAL 2016 qual A

    CODE FESTIVAL 2016 qual A A - CODEFESTIVAL 2016 -- #include <bits/stdc++.h> #define fi first # ...

  2. 【AtCoder】CODE FESTIVAL 2016 qual B

    CODE FESTIVAL 2016 qual B A - Signboard -- #include <bits/stdc++.h> #define fi first #define s ...

  3. 【AtCoder】CODE FESTIVAL 2016 qual C

    CODE FESTIVAL 2016 qual C A - CF -- #include <bits/stdc++.h> #define fi first #define se secon ...

  4. Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution

    Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution 题目链接:https://atcoder.jp/contests/cf16- ...

  5. Atcoder CODE FESTIVAL 2016 qual C 的E题 Encyclopedia of Permutations

    题意: 对于一个长度为n的排列P,如果P在所有长度为n的排列中,按照字典序排列后,在第s位,则P的value为s 现在给出一个长度为n的排列P,P有一些位置确定了,另外一些位置为0,表示不确定. 现在 ...

  6. CODE FESTIVAL 2016 qualA Grid and Integers

    划年代久远的水 题意 有一个R*C的棋盘,要求在每个格子上填一个非负数,使得对任意一个2*2的正方形区域,左上角和右下角的数字之和等于左下角和右上角的数字之和.有一些格子已经被填上了数字,问现在能否满 ...

  7. [CODE FESTIVAL 2016]Problem on Tree

    题意:给一棵树,对于一个满足以下要求的序列$v_{1\cdots m}$,求最大的$m$ 对$\forall1\leq i\lt m$,路径$(v_i,v_{i+1})$不包含$v$中除了$v_i,v ...

  8. [CODE FESTIVAL 2016]Encyclopedia of Permutations

    题意:给定一个排列,其中有可能有一些未确定的数,求出所有可能的排列的排名之和 首先我们要知道怎么算一个给定排列的排名,设它为$p_{1\cdots n}$ 排名即为比它小的排列数$+1$,对于每一个比 ...

  9. CODE FESTIVAL 2016 Grand Final 题解

    传送门 越学觉得自己越蠢--这场除了\(A\)之外一道都不会-- \(A\) 贪心从左往右扫,能匹配就匹配就好了 //quming #include<bits/stdc++.h> #def ...

随机推荐

  1. java servlet jsp 导入boostrap css js

    1.在导入boostrap.css的时候注意了 一定要注意路径,你知道把js和css包放在servlet服务器的静态路径下面就是 lib 文件夹路径下,直接使用 lib/js/boostrap.css ...

  2. CSS 竖线颜色渐变

    <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"& ...

  3. linux启动过程——(三)

  4. STM32-内存管理

    转载:http://www.cnblogs.com/guozhikai/p/6031904.html #ifndef __MALLOC_H #define __MALLOC_H #include &q ...

  5. 【uva10779】收集者的难题

    按照题意建模就行了. #include<bits/stdc++.h> #define naive 0 #define inf 1000000007 using namespace std; ...

  6. HDU 6188 Duizi and Shunzi 贪心

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6188 题意:给了n个数,然后现在问我们最多构成多少个对子和顺子,其中对子是2个相同的牌,顺子是3个连续 ...

  7. python爬虫实战——5分钟做个图片自动下载器

      python爬虫实战——图片自动下载器 制作爬虫的基本步骤 顺便通过这个小例子,可以掌握一些有关制作爬虫的基本的步骤. 一般来说,制作一个爬虫需要分以下几个步骤: 分析需求(对,需求分析非常重要, ...

  8. windows访问linux共享文件夹

    1.windows的网上邻居,是通过smb协议来共享信息的,如果需要给访问linux上的共享目录被windows访问到,需要linux有smb协议 sudo apt-get install samba ...

  9. linux命令(6):tar命令

    压缩方法:tar zcvf test.tar.gz test [表示把文件夹目录压缩成test.tar.gz文件保存] 解压方法:tar zxvf test.tar.gz –C /home [表示解压 ...

  10. Django web框架之权限管理一

    1. 需求分析: 准备:创建独立app, rbac #权限管理模块/组件 app01 #应用 分配权限,URL 2. 数据库设计 2.1 设计思路 第一版: 权限表: ID url title is_ ...