P7832 [CCO2021] Bread First Search

题目描述

这个国家有 nn 个城市和 mm 条双向道路。

有一个人要游览这个国家,但他很讲究。他要求游览线路必须是一个 BFS(Bread First Search,面包优先搜索)序,必须访问每个城市各一次,且满足以下条件:

  • 首个城市可以任选;
  • 除了首个城市外,每个城市被访问前至少有一个相邻城市已经被访问过;
  • 每个城市与首个城市的距离单调不降。其中两个城市的距离定义为它们路径边数的最小值。

这个人还有强迫症,一定要按照编号 1 \sim n1∼n 的顺序将每个城市访问一次。为了使这条游览线路符合上述所有要求,政府需要新修若干条道路。请问最少需要新修多少条道路?

输入格式

第一行,两个整数 n, mn,m;

接下来 mm 行,每行两个整数 a, ba,b,表示这个国家的一条双向道路。

输出格式

一行,一个整数,表示所求的值。

输入输出样例

输入 #1      输出 #1
2 0          1

输入 #2     输出 #2
6 3         2
1 3
2 6
4 5

说明/提示

样例 #2 解释

一种符合要求的方式是,在城市 1, 21,2 之间修一条路,在城市 1, 41,4 之间修一条路。此时城市 11 与城市 1 \sim 61∼6 的距离分别是 0, 1, 1, 1, 2, 20,1,1,1,2,2。

数据范围

对于 \frac{11}{32}3211​ 的数据,1 \leq n \leq 2001≤n≤200;

对于 62.5\%62.5% 的数据,1 \leq n \leq 5 \times 10^31≤n≤5×103;

对于 100\%100% 的数据,1 \leq n \leq 2 \times 10^51≤n≤2×105,0 \leq m \leq \min(2 \times 10^5, \frac{n(n - 1)}{2})0≤m≤min(2×105,2n(n−1)​),1 \leq a, b \leq n1≤a,b≤n,

代码:

#include<bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
//#define int long long
using namespace std;
inline int read()
{
    char c=getchar();int x=0;bool f=0;
    for(;!isdigit(c);c=getchar())f^=!(c^45);
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
    if(f)x=-x;return x;
}

#define fi first
#define se second
#define pb push_back
#define mkp make_pair
typedef pair<int,int>pii;
typedef vector<int>vi;

#define maxn 200005
#define inf 0x3f3f3f3f

bool vis[maxn];
int n,m,f[maxn],sum,mn[maxn],mx[maxn],g[maxn];
vi e[maxn];
void addin(int x){sum+=(!vis[x]),vis[x]=1;}

signed main()
{
	n=read(),m=read();
	For(i,1,n)mn[i]=n+1;
	For(i,1,m){
		int u=read(),v=read();
		mn[u]=min(mn[u],v);
		mn[v]=min(mn[v],u);
		mx[u]=max(mx[u],v);
		mx[v]=max(mx[v],u);
		e[min(u,v)].pb(max(u,v));
	}
	For(i,1,n)mx[i]=max(mx[i],mx[i-1]);
	memset(f,63,sizeof f);
//	For(j,2,n){
//		int sum=0,p=j-1;
//		For(i,max(j,mx[j-1]),n){
//			while(p<i) ++p,sum+=(mn[p]>j-1);
//			f[i]=min(f[i],f[j-1]+sum);
//		}
//	}
	For(j,1,n-1){
		f[j]=min(f[j],f[j-1]+1);
		int nowf=(j==1?0:f[j]);
		addin(j);
		for(auto v:e[j])addin(v);
		// mx[j]
		int to=max(mx[j],j+1);
		f[to]=min(f[to],nowf+to-sum);
	}
	cout<<f[n];
	return 0;
}

代码 好像有点少

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值