1106D. Lunar New Year and a Wander
Tags:BFS Dijkstra 堆/优先队列
题目描述
给定一个有 V V V 个点 E E E 条边的无向连通图(顶点编号从 1 1 1 到 V V V,可有重边自环)
L
u
n
a
r
Lunar
Lunar 这个人从顶点
1
1
1 出发,然后在图中任意游荡
(只要沿着图中存在的边走就行,可以往返走),每当她第一次访问到某个点时输出此点的编号。那么当她把每个点都至少访问了一遍后就会得到一个
1
1
1 到
V
V
V 的排列。求所有可能存在的排列中字典序最小者。
输入
1 1 1 组。第一行两个数 V V V 和 E E E,代表顶点个数和边的条数
接下来 E E E 行每行 2 2 2 个数代表一条无向边连接的两个顶点
范围:
1
≤
V
≤
1
0
5
1\le V \le 10^5
1≤V≤105 ;
1
≤
E
≤
1
0
5
1\le E \le 10^5
1≤E≤105。
输出
一个
1
1
1 到
V
V
V 的排列(数字之间打一个空格),应是所有走法可能中字典序最小者。
输入样例 1
5 5
1 4
3 4
5 4
3 2
1 5
输出样例 1
1 4 3 2 5
输入样例 2
10 10
1 4
6 8
2 5
3 7
9 4
5 6
3 4
8 10
8 9
1 10
输出样例 2
1 4 3 7 9 8 6 5 2 10
分析
这道题其实挺直觉的。每次从已访问子图(已经访问过的点所构成的连通图)的邻接的一批顶点中选一个编号最小的扩展过去,按这样的顺序把每个点都访问到就得到了最小字典序的答案。是不是就是按一定顺序的 B F S BFS BFS ?(其实跟 D i j k s t r a Dijkstra Dijkstra 也有异曲同工之妙,因为二者都是每次从已访问子图的邻接点中挑一个扩展过去,只不过 D i j k s t r a Dijkstra Dijkstra 是选离已访问子图最近的点,而本题是选编号最小的点。)
又因为这里是稀疏图,所以邻接表存图就行。用最小堆维护进行带优先级的 B F S BFS BFS, B F S BFS BFS 序即为答案。
时间复杂度:循环 Θ ( V ) \Theta (V) Θ(V) 次,每次循环出队是 O ( log V ) O(\log V) O(logV) 的,入队则是所有循环均摊 O ( E log V ) O(E \log V) O(ElogV),总的 O ( ( V + E ) log V ) O((V+E) \log V) O((V+E)logV) 。
【 C G 】 【CG】 【CG】
这道题的易错点(针对我个人)在哪呢?主要是别偷懒
!
c
o
n
s
t
e
x
p
r
i
n
t
M
V
constexpr\ int\ MV
constexpr int MV 和
c
o
n
s
t
e
x
p
r
i
n
t
M
E
constexpr\ int\ ME
constexpr int ME 一定都要写,不要偷懒只写一个
M
V
MV
MV:
- 有时候点和边的范围不同
- 其实范围不同时还会强迫我去写俩定义,但是在范围相同时,如果又来个什么双向边,或者又来个什么扩边增边改图,同时如果又用的是 链式前向星 ,那用 M V MV MV 去开 e d g e [ M V ] edge[MV] edge[MV] 就越界了。
- 另外一个 T i p s Tips Tips:用邻接表时,开 s t d : : v e c t o r std::vector std::vector 数组时,用的确实还是 M V MV MV,而不是 M E ME ME。好像只有链式前向星涉及到 M E ME ME。
AC代码
对于STL已有的数据结构呢,我一般是坚持能用STL则用STL的原则。但是对于这个优先队列,可以的话我还是习惯用自己的。
STL的优先队列速度实在不行(即便开
O
2
O_2
O2 )
所以不喜勿喷啦~
#include <bits/stdc++.h>
#define _F0N(i,n) for(i=0;i<n;++i)
#define _FLR(i,l,r) for(i=l;i<r;++i)
#define _gF(_1,_2,_3,_F, ...) _F
#define F(...) _gF(__VA_ARGS__,_FLR,_F0N, ...)(__VA_ARGS__)
#define _FD0(i,n) for(i=0;i<=n;++i)
#define _FDL(i,l,r) for(i=l;i<=r;++i)
#define _gFD(_1,_2,_3,_FD, ...) _FD
#define FD(...) _gFD(__VA_ARGS__,_FDL,_FD0, ...)(__VA_ARGS__)
#define _G1(_1) int _1;sc(_1)
#define _G2(_1,_2) int _1,_2;sc(_1)sc(_2)
#define _G3(_1,_2,_3) int _1,_2,_3;sc(_1)sc(_2)sc(_3)
#define _gG(_1,_2,_3,_get, ...) _get
#define get(...) _gG(__VA_ARGS__,_G3,_G2,_G1, ...)(__VA_ARGS__)
#define OPER1(T,x1,b1) inline bool operator<(const T&o)const{return x1 b1 o.x1;}
#define OPER2(T,x1,b1,x2,b2) inline bool operator<(const T&o)const{return x1 b1 o.x1||x1==o.x1&&x2 b2 o.x2;}
#define OPER3(T,x1,b1,x2,b2,x3,b3) inline bool operator<(const T&o)const{return x1 b1 o.x1||x1==o.x1&&(x2 b2 o.x2||x2==o.x2&&x3 b3 o.x3);}
#define LL long long
#define ULL unsigned long long
#define sc(x) {register char _c=getchar(),_v=1;for(x=0;_c<48||_c>57;_c=getchar())if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=getchar());x*=_v;}
#define PC putchar
template<typename T>void PRT(const T a){if(a<0){PC(45),PRT(-a);return;}if(a>=10)PRT(a/10);PC(a%10+48);}
template<typename T>void UPRT(const T a){if(a>=10)UPRT(a/10);PC(a%10+48);}
#define CON constexpr
#define T_CASE int _CASE;sc(_CASE)for(int __=1;__<=_CASE;++__)
#define cincout cin.tie(0),ios::sync_with_stdio(false)
#define eps 1e-8
#define PI 3.141592653589793
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3fLL
#define endl '\n'
#define priority_queue priority_queue
#define PQ std::priority_queue
#define PR std::pair
#define vector vector
#define VI std::vector<int>
#define MII std::map<int,int>
#define MLI std::map<LL,int>
#define MSI std::map<std::string,int>
#define PII std::pair<int,int>
#define PLI std::pair<LL,int>
#define PSI std::pair<std::string,int>
#define MPFD(k) auto it=mp.find(k)
#define MIN(a, b) ((a)<(b)?(a):(b))
#define MIN3(a, b, c) (MIN(a, MIN(b, c)))
#define MAX(a, b) ((a)>(b)?(a):(b))
#define MAX3(a, b, c) (MAX(a, MAX(b, c)))
#define get_max(a,l,r,_max) auto _max=a[l];for(int _i=l+1,_r=r;_i<_r;++_i)if(_max<a[_i])_max=a[_i]
#define get_min(a,l,r,_min) auto _min=a[l];for(int _i=l+1,_r=r;_i<_r;++_i)if(_min<a[_i])_min=a[_i]
#define ABS(a) (a>0?a:-a)
#define FABS(a) (a>0?a:-a)
#define log2n(x) (log(x)/0.69314718055995)
#define PB emplace_back
#define EB emplace_back
#define EK else break
#define ALL(X) (X).begin(),(X).end()
#define SORT(X) std::sort(ALL(X))
#define SORTD(X) std::sort(ALL(X),std::greater<decltype((X)[0])>())
#define swap(a, b) do{auto _t=a; a=b; b=_t;}while(0)
#define mem0(a) memset(a,0,sizeof(a))
#define memf1(a) memset(a,-1,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
CON int MV(1e5 + 7);
CON int ME(2e5 + 7); // 双向边,别忘了二倍
bool vis[MV];
template <class Type, int MN>
class KPQ
{
#define ChosenType Type
#define CMP <
#define _pd(_r) int p=_r;for(int c,E=cnt>>1;p<=E;p=c){c=p<<1;if(c!=cnt&&heap[c+1] CMP heap[c])++c;if(heap[c] CMP tp)heap[p]=heap[c];else break;}heap[p]=tp
public:Type heap[2 * MN];int cnt;public:KPQ(const ChosenType MS):cnt(0){*heap=MS;}void push(const ChosenType data){register int i=++cnt;for(;data CMP heap[i>>1];i>>=1)heap[i]=heap[i>>1];heap[i]=data;}void pop(void){const ChosenType tp=heap[cnt--];_pd(1);}inline const ChosenType top(void){return heap[1];}
};
KPQ<int, MV> pq(-1);
struct Edge
{
int next;
int dest;
} edge[ME];
int head[ME], tot;
inline void add_edge(const int u, const int v)
{
edge[++tot].next = head[u];
edge[tot].dest = v;
head[u] = tot;
}
inline void visit(const int index)
{
vis[index] = true;
pq.push(index);
}
int main()
{
get(V, E)
for (int i=0; i<E; ++i)
{
get(u, v)
add_edge(u, v);
add_edge(v, u);
}
visit(1);
while (pq.cnt)
{
int u = pq.top();
pq.pop();
PRT(u), PC(32);
for (int i=head[u]; i; i=edge[i].next)
{
const int v = edge[i].dest;
if (not vis[v])
{
visit(v);
}
}
}
return 0;
}
(什么?过个年 CF 就炸了?)