D. Lunar New Year and a Wander CodeForces - 1106D(类prim+类bfs)

Lunar New Year is approaching, and Bob decides to take a wander in a nearby park.

The park can be represented as a connected graph with n nodes and m bidirectional edges. Initially Bob is at the node 1 and he records 1 on his notebook. He can wander from one node to another through those bidirectional edges. Whenever he visits a node not recorded on his notebook, he records it. After he visits all nodes at least once, he stops wandering, thus finally a permutation of nodes a1,a2,…,an is recorded.

Wandering is a boring thing, but solving problems is fascinating. Bob wants to know the lexicographically smallest sequence of nodes he can record while wandering. Bob thinks this problem is trivial, and he wants you to solve it.

A sequence x is lexicographically smaller than a sequence y if and only if one of the following holds:

x is a prefix of y, but x≠y (this is impossible in this problem as all considered sequences have the same length);
in the first position where x and y differ, the sequence x has a smaller element than the corresponding element in y.
Input
The first line contains two positive integers n and m (1≤n,m≤105), denoting the number of nodes and edges, respectively.

The following m lines describe the bidirectional edges in the graph. The i-th of these lines contains two integers ui and vi (1≤ui,vi≤n), representing the nodes the i-th edge connects.

Note that the graph can have multiple edges connecting the same two nodes and self-loops. It is guaranteed that the graph is connected.

Output
Output a line containing the lexicographically smallest sequence a1,a2,…,an Bob can record.

Examples
Input
3 2
1 2
1 3
Output
1 2 3
Input
5 5
1 4
3 4
5 4
3 2
1 5
Output
1 4 3 2 5
Input
10 10
1 4
6 8
2 5
3 7
9 4
5 6
3 4
8 10
8 9
1 10
Output
1 4 3 7 9 8 6 5 2 10
Note
In the first sample, Bob’s optimal wandering path could be 1→2→1→3. Therefore, Bob will obtain the sequence {1,2,3}, which is the lexicographically smallest one.

In the second sample, Bob’s optimal wandering path could be 1→4→3→2→3→4→1→5. Therefore, Bob will obtain the sequence {1,4,3,2,5}, which is the lexicographically smallest one.

题意:给你一个图,问你遍历这个图,经过的点可以组成的最小序列是什么,一条路可以走多次。

思路:最开始的思路是用一个小到大的优先队列存路径,然后dfs遍历一遍,得到的路径应该就是最小序列,然后答案错误了。
代码如下:

#include<bits/stdc++.h>
#define LL long long
#define Max 100005
#define Mod 1e9+7
const LL mod=1e9+7;
const LL inf=0x3f3f3f3f;
using namespace std;
priority_queue<int,vector<int>,greater<int> > a[Max];
queue<int>s;
int n,m;
int vis[Max];
void dfs(int dis)
{
    int t;
    while(a[dis].size()){
        t=a[dis].top();
        a[dis].pop();
        if(!vis[t]){
            s.push(t);
            vis[t]=1;
            dfs(t);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=0;i<m;i++){
        scanf("%d%d",&x,&y);
        a[x].push(y);
        a[y].push(x);
    }
    vis[1]=1;
    s.push(1);
    dfs(1);
    while(s.size())
    {
        printf("%d ",s.front());
        s.pop();
    }
    return 0;
}

为什么会答案错误呢,可以反证
如果一个图如下:
在这里插入图片描述
如果我们用dfs的话得到的序列为:1 4 3 7 5
而正确答案应该是 1 4 3 5 7
为什么呢? 因为题意说了,一条路可以走多次,所以走到3后可以 3->4 4->1 1->5 5->1 1->4 4->7
得到1 4 3 7 5 ,所以我们可以想到第二个思路:类似最短路的算法
思路二:假设集合A={1} ,因为先从1开始,从1开始找到最小点,加入到集合中,如上图为4,将4加入到集合,A={1,4},再到集合A中找与之相关的最小的点,找到3,加入集合,以此类推最后就是答案了,实际上就这是prim算法

#include<bits/stdc++.h>
#define LL long long
#define Max 100005
#define Mod 1e9+7
const LL mod=1e9+7;
const LL inf=0x3f3f3f3f;
using namespace std;
priority_queue<int,vector<int>,greater<int> > a[Max];
queue<int>s;
int n,m;
int vis[Max],step[Max];
void fun()
{
    int len=1,c=1;
    step[0]=1;
    vis[1]=1;
    s.push(1);
    int mins=inf;
    while(c<n)
    {
        for(int i=0;i<len;i++){
            if(a[step[i]].size()==0)
                continue;
            while(vis[a[step[i]].top()] && a[step[i]].size()>=1){
                a[step[i]].pop();
            }
            if(a[step[i]].size())
                mins=min(a[step[i]].top(),mins);
        }
        vis[mins]=1;
        step[len++]=mins;
        s.push(mins);
        mins=inf;
        c++;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=0;i<m;i++){
        scanf("%d%d",&x,&y);
        a[x].push(y);
        a[y].push(x);
    }
    fun();
    while(s.size())
    {
        printf("%d ",s.front());
        s.pop();
    }
    return 0;
}

上面这个代码超时了,因为循环执行了太多次,所以得优化,想一下我们循环的目的是为了找到最小的点,所以可以使用一个优先队列,用类bfs的算法,将答案求出来

#include<bits/stdc++.h>
#define LL long long
#define Max 100005
#define Mod 1e9+7
const LL mod=1e9+7;
const LL inf=0x3f3f3f3f;
using namespace std;
priority_queue<int,vector<int>,greater<int> > a[Max],p;
int vis[Max];
queue<int>s;
int n,m;
void fun()
{
    p.push(1);
    vis[1]=1;
    s.push(1);
    while(p.size())
    {
        int t=p.top();
        p.pop();
        if(!vis[t]){
            s.push(t);
            vis[t]=1;
        }
        while(a[t].size()){
            int f=a[t].top();
            a[t].pop();
            if(!vis[f]){
                 p.push(f);
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=0;i<m;i++){
        scanf("%d%d",&x,&y);
        a[x].push(y);
        a[y].push(x);
    }
    fun();
    while(s.size())
    {
        printf("%d ",s.front());
        s.pop();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Gee_Zer/article/details/89194086