((蓝桥杯 刷题全集)【备战(蓝桥杯)算法竞赛-第3天】( 从头开始重新做题,记录备战竞赛路上的每一道题 )距离蓝桥杯还有64天

news2025/1/16 9:11:46

🏆🏆🏆🏆🏆🏆🏆
欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)
 
文章字体风格:
红色文字表示:重难点✔★
蓝色文字表示:思路以及想法✔★
 
如果大家觉得有帮助的话,感谢大家帮忙
点赞!收藏!转发!

 
我的qq号是:1210931886,欢迎大家加群,一起学习,互相交流,共同进步🎉🎉✨✨
🥇🥇🥇🥇🥇🥇🥇

蓝桥杯系列,为大家提供

  1. 做题全集,备战蓝桥杯,就做这个系列的题即可
  2. 一个大概的做题规划——大家最好在此基础上提前两个月准备

备战蓝桥杯就刷这些题
第一天博客链接
第二天博客链接

蓝桥杯 刷题全集

        • 1. 排列数字(3分钟)
        • 2. n-皇后问题
        • 1. 走迷宫
            • 二刷总结(队列存储一个节点pair<int,int>)
            • 三刷总结 走过的点标记上距离(既可以记录距离,也可以判断是否走过)
        • ★ ★ 例题2. 八数码
            • 二刷总结
        • 1. 树的重心
          • 二刷总结( 注意无向图的遍历 )
        • 1. 图中点的层次( 无权最短路 )
        • 1. 有向图的拓扑排序 ✔12.24
            • 做题总结
        • 1. Dijkstra求最短路 I(邻接矩阵)✔12.24
            • 二刷总结
        • ★ 1. Dijkstra求最短路 II(邻接表)✔12.24
            • 二刷总结
        • 模板 (遍历所有边只走一步)
        • 1. 有边数限制的最短路 ✔ 12.24
        • 做题总结:
        • 1. spfa求最短路 ✔12.24
        • 做题总结:
      • 例题 spfa判断负环 ✔12.26
        • 刷题总结
        • 1. Floyd求最短路 ✔12.26
          • 做题总结
        • Prim算法求最小生成树 ✔12.27
          • 做题总结

1. 排列数字(3分钟)

每次遍历dfs参数是 遍历的坑位
原题链接

#include<iostream>
using namespace std;
const int N = 10;
int path[N];//保存序列
int state[N];//数字是否被用过
int n;
void dfs(int u)//u表示的是 第几个坑位
{
    if(u > n)//数字填完了,输出
    {
        for(int i = 1; i <= n; i++)//输出方案
            cout << path[i] << " ";
        cout << endl;
    }

    for(int i = 1; i <= n; i++)//空位上可以选择的数字为:1 ~ n
    {
        if(!state[i])//如果数字 i 没有被用过
        {
            path[u] = i;//放入空位
            state[i] = 1;//数字被用,修改状态
            dfs(u + 1);//填下一个位
            state[i] = 0;//回溯,取出 i
        }
    }
}

int main()
{

    cin >> n;
    dfs(1);
}

2. n-皇后问题

原题链接

方法 1. 按行遍历(过程中有回溯、剪枝)

思想:

  1. 每次递归中,遍历一行的元素,如果可以放皇后,就递归到下一行,下一行中不行了,就返回来,回溯,
//cpp
#include <iostream>
using namespace std;

const int N = 11;

char q[N][N];//存储棋盘
bool dg[N * 2], udg[N * 2], cor[N];
//点对应的两个斜线以及列上是否有皇后

int n;

void dfs(int r)
{
    if(r == n)//放满了棋盘,输出棋盘
    {
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
                cout << q[i][j];
            cout << endl;
        }
        cout << endl;
        return;
    }

    for(int i = 0; i < n; i++)//第 r 行,第 i 列 是否放皇后
    {
        if(!cor[i] && !dg[i + r] && !udg[n - i + r])//不冲突,放皇后
        {
            q[r][i] = 'Q';
            cor[i] = dg[i + r] = udg[n - i + r] = 1;//对应的 列, 斜线 状态改变
            dfs(r + 1);//处理下一行
            cor[i] = dg[i + r] = udg[n - i + r] = 0;//恢复现场
            q[r][i] = '.';
        }
    }
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            q[i][j] = '.';
    dfs(0);
    return 0;
}

方法2. 按每个元素遍历(没有减枝)

// 不同搜索顺序 时间复杂度不同  所以搜索顺序很重要!
#include <iostream>
using namespace std;
const int N = 20;

int n;
char g[N][N];
bool row[N], col[N], dg[N], udg[N]; 
// 因为是一个个搜索,所以加了row

// s表示已经放上去的皇后个数
void dfs(int x, int y, int s)
{
    // 处理超出边界的情况
    if (y == n) y = 0, x ++ ;

    if (x == n) { // x==n说明已经枚举完n^2个位置了
        if (s == n) { // s==n说明成功放上去了n个皇后
            for (int i = 0; i < n; i ++ ) puts(g[i]);
            puts("");
        }
        return;
    }
    
//和上面按行遍历的差别就是,这里没有循环

    // 分支1:放皇后
    if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n]) {
        g[x][y] = 'Q';
        row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
        dfs(x, y + 1, s + 1);
        row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
        g[x][y] = '.';
    }

    // 分支2:不放皇后
    dfs(x, y + 1, s);
}


int main() {
    cin >> n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            g[i][j] = '.';

    dfs(0, 0, 0);

    return 0;
}

1. 走迷宫

二刷总结(队列存储一个节点pair<int,int>)
三刷总结 走过的点标记上距离(既可以记录距离,也可以判断是否走过)
  1. bfs 需要队列
  2. ==走过的点标记上距离(既可以记录距离,也可以判断是否走过)==没走过的置为-1
  3. (队列存储一个节点pair<int,int>)

原题链接
原题链接

#include<iostream>
#include<cstring>

using namespace std;

int n,m;
int p[110][110];
int d[110][110];
int dx[4] = {-1,0,1,0};
int dy[4] = {0,-1,0,1};

pair<int,int> q[110*110];
int hh,tt=-1;

void bfs()
{
    q[++tt] = {1,1};
    p[1][1] = 1;
    d[1][1] = 0;
    while(hh<=tt)
    {
        pair<int,int> item = q[hh++];
        for(int i = 0; i < 4; i++)
        {
            int x = item.first;
            int y = item.second;
            //cout << x << ' ' << y << endl;
            if(p[x+dx[i]][y+dy[i]]!=1 && x+dx[i]<=n && x+dx[i] > 0 && y+dy[i] <=m && y+dy[i] >0)
            {
                d[x+dx[i]][y+dy[i]] = d[x][y] + 1;
                q[++tt] = {x+dx[i],y+dy[i]};
                p[x+dx[i]][y+dy[i]] = 1;
            }
        }
    }
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i<=n; i++)
    {
        for(int j = 1; j<=m; j++)
            cin >> p[i][j];
    }
    
    bfs();
    
    cout << d[n][m];
    
    return 0;
}

★ ★ 例题2. 八数码

原题链接

二刷总结
  1. 字符串存储二维数组
  2. 每种情况对应一个移动距离,正好就用map
  3. 字符串有find函数,map有count函数
  4. map的count就可以判别 该位置是否走过
    补充一点就是,一种情况只能走过一次!不可能走走走地出现与之前一样的情况,这不就是白走了嘛
  5. 先swap才能接着判断
#include<iostream>
#include<unordered_map>
#include<cstring>
#include<queue>

using namespace std;

int bfs(string s)
{
    queue<string> q;
    q.push(s);
    int dx[4] = { 1,0,-1,0 },
        dy[4] = { 0,-1,0,1 };
    unordered_map<string, int> d;
    d[s] = 0;

    while (!q.empty())
    {
        string f = q.front();
        q.pop();
        if (f == "12345678x")
            return d[f];
        int df = d[f];
        int k = f.find("x");
        int x = k / 3;
        int y = k % 3;
        for (int i = 0; i < 4; i++)
        {
            if (x + dx[i] <= 2 && x + dx[i] >= 0 && y + dy[i] <= 2 && y + dy[i] >= 0)
            {
                swap(f[k], f[(x + dx[i]) * 3 + y + dy[i]]);
                if (!d.count(f))
                {
                    d[f] = df + 1;
                    q.push(f);
                }
                swap(f[k], f[(x + dx[i]) * 3 + y + dy[i]]);
            }
        }
    }
    return -1;
}

int main()
{
    char ch;
    string s;
    for (int i = 0; i < 9; i++)
    {
        cin >> ch;
        s += ch;
    }
    cout << bfs(s);
    return 0;
}

1. 树的重心

原题链接

二刷总结( 注意无向图的遍历 )
  1. 无向图的节点数 是 2倍
  2. 无向图的连接
void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
  1. 遍历过的点标记一下,不再遍历,因为无向图可能往回遍历
#include<iostream>
#include<cstring>

using namespace std;

const int N = 2e5 + 10;

int h[N], e[N], ne[N], idx;
bool st[N];

int sum;
int n;
int res;

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int q = 0;
int dfs(int x)
{
    if (x == -1)return 0;
    st[x] = true;

    int xx = 0;
    int xxx = 0;
    for (int i = h[x]; i != -1; i = ne[i])
    {
        if (st[e[i]] == false)
        {
            int s = dfs(e[i]);
            xx = max(s, xx);
            xxx += s;
        }
    }
    //cout << e[x] << "下面的值" << xxx << endl;
    sum = max(xx, n - xxx - 1);
    if (sum < res)
    {
        res = sum;
        q = x;
    }
    return xxx + 1;

}

int main()
{
    memset(h, -1, sizeof h);
    cin >> n;

    int a, b;
    while (cin >> a >> b)
        add(a, b), add(b, a);

    res = n;
    dfs(1);

    cout << res;

    return 0;
}

1. 图中点的层次( 无权最短路 )

原题链接
原题链接

#include<iostream>
#include<queue>
#include<cstring>

using namespace std;

const int N = 1e5 + 10;

int e[N], ne[N], h[N], idx;
int d[N];
bool st[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void bfs(int x)
{
    queue<int> q;
    q.push(x);

    while (q.size())
    {
        int u = q.front();
        q.pop();
        st[u] = true;
        int dd = d[u];
        for (int i = h[u]; i != -1; i = ne[i])
        {
            //这里可以改进,因为可以用d 判断是否遍历过该节点
            if (st[e[i]] == false)
            {
                st[e[i]] = true;
                q.push(e[i]);
                d[e[i]] = min(d[e[i]], dd + 1);
            }
        }

    }

}

int main()
{
    memset(h, -1, sizeof h);
    memset(d, 0x3f, sizeof d);
    d[1] = 0;
    int n, k;
    cin >> n >> k;

        for (int i = 1; i <= k; i++)
        {
            int a, b;
            cin >> a >> b;
            add(a, b);
        }

    bfs(1);
    if(d[n] != 0x3f3f3f3f)
        cout << d[n];
    else
        cout << -1;
    return 0;
}

1. 有向图的拓扑排序 ✔12.24

做题总结
  1. 拓扑是一个宽搜
  2. 遍历顺序是 度为0(可能有多个为0的)
  3. 可以用q[] 表示队列,这样就用一个队列就可以存储拓扑的结果和 遍历的过程了(也就是拓扑排序的遍历过程,就是答案顺序)

原题链接

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=100010;
int h[N],e[N],ne[N],idx;
int n,m;
int q[N],d[N];//q表示队列,d表示点的入度

void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}

bool topsort()
{
    int hh=0,tt=-1;
    for(int i=1;i<=n;i++)
     if(!d[i]) 
     q[++tt]=i;//将入度为零的点入队
    while(hh<=tt)
    {
        int t=q[hh++];
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            d[j]--;//删除点t指向点j的边
            if(d[j]==0)//如果点j的入度为零了,就将点j入队
            q[++tt]=j;
        }
    }
    return tt==n-1;
    //表示如果n个点都入队了话,那么该图为拓扑图,返回true,否则返回false
}

int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof(h));//如果程序时间溢出,就是没有加上这一句
    for(int i=0;i<m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);//因为是a指向b,所以b点的入度要加1
        d[b]++;
    }
    if(topsort()) 
    {
        for(int i=0;i<n;i++)
        printf("%d ",q[i]);
        //经上方循环可以发现队列中的点的次序就是拓扑序列
        //注:拓扑序列的答案并不唯一,可以从解析中找到解释
        puts("");
    }
    else
    puts("-1");

    return 0;
}
#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

const int N = 1e5+10;

bool st[N];
int e[N],ne[N],idx,h[N];
int b[N];//每个节点的入读

int n,k;  

queue<int> q,ans;

void bfs()
{
    while(q.size())
    {
        int f = q.front();
        q.pop();
        for(int i = h[f]; i != -1; i = ne[i])
        {
                b[e[i]]--;
                if(b[e[i]]==0)
                {
                    ans.push(e[i]);
                    q.push(e[i]);
                }
            
        }
        
    }
    
}

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

int main()
{ 
    memset(h,-1,sizeof h);
    cin >> n >> k;
    for(int i = 1; i <= k; i++)
    {
        int a,bb;
        cin >> a >> bb;
        add(a,bb);
        b[bb]++;
    }
    
    for(int i = 1; i <= n; i++)
    {
        if(b[i]==0)
        {
            //cout << i << endl;
            q.push(i);
            ans.push(i);
        }
    }
    bfs();
        if(ans.size()!=n)
    {
        cout << -1;
        return 0;
    }
    //cout << ans.size() << endl;
    
    while(ans.size())
    {
        cout << ans.front() << ' ';
        ans.pop();
    }
    
    return 0;
}

在这里插入图片描述

1. Dijkstra求最短路 I(邻接矩阵)✔12.24

原题链接
刷题总结

  1. 稀疏矩阵 和 疏密矩阵(疏密矩阵 可以用 邻接矩阵存储方式)
  2. 邻接矩阵直接就可以存储 边距离了
  3. d存储到1节点的距离
二刷总结
  1. dijk就是两步 :1. 在dist里选出最小值 2.遍历dist更新
    如何选(如下)
int t = -1;
for (int j = 1; j <= n; j ++ )
    if (!st[j] && (t == -1 || dist[t] > dist[j]))
        t = j;

★ 1. Dijkstra求最短路 II(邻接表)✔12.24

原题链接

二刷总结
  1. 利用小根堆存储,元素是PII
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;

typedef pair<int,int> PII;

const int N = 1e6+10;

int e[N],ne[N],h[N],idx;
int w[N];
int d[N];
bool st[N];

int n,m;

void add(int a,int b,int c)
{
    e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++;
}

void dijkstra()
{
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    d[1] = 0;
    heap.push({0,1});
    while(heap.size())
    {
        auto item = heap.top();
        heap.pop();
        
        if(st[item.second]==true)continue;
        st[item.second]=true;
        
        for(int i = h[item.second]; i!= -1; i = ne[i])
        {
            if(d[e[i]] > w[i] + item.first)
            {
                d[e[i]] = w[i] + item.first;
                heap.push({d[e[i]],e[i]});
            }
        }
        
    }
}

int main()
{
    memset(d,0x3f,sizeof d);
    memset(h,-1,sizeof h);
    cin >> n >> m;
    for(int i = 0; i < m; i++)
    {
        int a,b,c;
        cin >> a >> b >> c;
        add(a,b,c);
    }
    
    dijkstra();
    
    if(d[n]!=0x3f3f3f3f)
        cout << d[n];
    else
        cout << -1return 0;
}

模板 (遍历所有边只走一步)

在这里插入图片描述

int n, m;       // n表示点数,m表示边数
int dist[N];        // dist[x]存储1到x的最短路距离

struct Edge     // 边,a表示出点,b表示入点,w表示边的权重
{
    int a, b, w;
}edges[M];

// 求1到n的最短路距离,如果无法从1走到n,则返回-1。
int bellman_ford()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    // 如果第n次迭代仍然会松弛三角不等式,就说明存在一条长度是n+1的最短路径,由抽屉原理,路径中至少存在两个相同的点,说明图中存在负权回路。
    for (int i = 0; i < n; i ++ )
    {
        for (int j = 0; j < m; j ++ )
        {
            int a = edges[j].a, b = edges[j].b, w = edges[j].w;
            if (dist[b] > dist[a] + w)
                dist[b] = dist[a] + w;
        }
    }

    if (dist[n] > 0x3f3f3f3f / 2) return -1;
    return dist[n];
}

1. 有边数限制的最短路 ✔ 12.24

原题链接

做题总结:

  1. dijkstra不能处理 负权边
    在这里插入图片描述
  2. 由于有k的限制,所以每次遍历一条边的时候,需要用备份数据,因为可能会发生数据改变(这样可能导致一次遍历所有边直接到n点了)
  3. 有可能出现n节点连接的是负边,那么我们就让n节点的值 > 0x3f3f3f3f/2 这样就可以了
#include<iostream>
#include<cstring>

using namespace std;

const int N = 510, M = 10010;

struct Edge {
    int a;
    int b;
    int w;
} e[M];//把每个边保存下来即可
int dist[N];
int back[N];//备份数组防止串联
int n, m, k;//k代表最短路径最多包涵k条边

int bellman_ford() {
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    for (int i = 0; i < k; i++) {//k次循环
        memcpy(back, dist, sizeof dist);
        for (int j = 0; j < m; j++) {//遍历所有边
            int a = e[j].a, b = e[j].b, w = e[j].w;
            dist[b] = min(dist[b], back[a] + w);
            //使用backup:避免给a更新后立马更新b, 这样b一次性最短路径就多了两条边出来
        }
    }
    if (dist[n] > 0x3f3f3f3f / 2) return -1;
    else return dist[n];

}

int main() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < m; i++) {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        e[i] = {a, b, w};
    }
    int res = bellman_ford();
    if (res == -1) puts("impossible");
    else cout << res;

    return 0;
}

1. spfa求最短路 ✔12.24

原题链接

做题总结:

  1. 和宽搜差不多,只是可能会 返回走(但距离值更新了,就把这个节点入队列再处理一次)
#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

const int N = 1e5+10;
int e[N],ne[N],h[N],idx;
int w[N];

bool st[N];

int n,m;

void add(int x,int y,int c)
{
    e[idx] = y,ne[idx] = h[x],w[idx] = c,h[x] = idx++;
}

int d[N];

void spfa()
{
    memset(d,0x3f,sizeof d);
    d[1] = 0;
    queue<int> q;
    q.push(1);
    st[1] = true;
    while(q.size())
    {
        auto f = q.front();
        q.pop();
        st[f] = false;
        for(int i = h[f]; i != -1; i = ne[i])
        {
            int j = i;
            if(d[e[j]] > d[f] + w[j])
            {
                d[e[j]] = d[f] + w[j];
            if(st[e[j]]==false)
            {
                q.push(e[j]);
                st[e[j]] = true;
            }
                
            }
        }
    }
}

int main()
{
    cin >> n >> m;
    memset(h,-1,sizeof h);
    for(int i = 0; i < m; i++)
    {
        int x,y,c;
        cin >> x >> y >> c;
        add(x,y,c);
    }
    
    spfa();
    if(d[n] == 0x3f3f3f3f)
        cout << "impossible";
    else
        cout << d[n];
    return 0;
}

原题链接

  1. 什么是负环
    在这里插入图片描述
    图1中:2 到 3 到 4 到 2 路径长度为 -10
    图2中:2 到 3 到 4 到 2 路径长度为 10

图1才叫负环
图2不是负环

  1. 出现负环会怎么样
    但出现负环的时候,如果我们要去求1到n的最短路,那么过程中,一定会在这个负环中一直转圈,导致路程可以变为负无穷

  2. 怎么判断图中是否有负环?
    综上,我们就采取求最小路径的方式(但是本题不是求最短路),当我们求最短路径的过程中,发现有一段路径重复走,那么就说明一定出现了负环

问题来了:怎么判断某段路径在重复走
我们想,1到n号点 最多才可能走了n-1条边
如果我们发现 到某点时 已经走了 大于等于n条边,那么一定就是有负环了
由于我们不知道 1 到 x点最多可能有多少条边,但一定不会超过 n - 1 条边,所以我们就都用 大于等于n条边去判断

例题 spfa判断负环 ✔12.26

原题链接

在这里插入图片描述

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 2010, M = 10010;

int n, m;
int h[N], w[M], e[M], ne[M], idx;
int dist[N], cnt[N];
bool st[N];

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}

bool spfa()
{
    queue<int> q;

    for (int i = 1; i <= n; i ++ )
    {
        st[i] = true;
        q.push(i);
    }

    while (q.size())
    {
        int t = q.front();
        q.pop();

        st[t] = false;

        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                cnt[j] = cnt[t] + 1;

                if (cnt[j] >= n) return true;
                if (!st[j])
                {
                    q.push(j);
                    st[j] = true;
                }
            }
        }
    }

    return false;
}

int main()
{
    scanf("%d%d", &n, &m);

    memset(h, -1, sizeof h);

    while (m -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }

    if (spfa()) puts("Yes");
    else puts("No");

    return 0;
}

刷题总结

  1. e,ne,h,idx 用于存储边,所以数值应该与边一样多
  2. 把所有点都入队列,防止不是连通图
  3. dist里存储多少都可以,因为我们只需判断负权回路
  4. 当一个点所走的路径长度大于n,那么就一定有负边,因为最多就是n正常的话。
  5. 一定要有st数组,判断是否再走这个点

在这里插入图片描述

1. Floyd求最短路 ✔12.26

原题链接

做题总结
  1. 用二维数组存储更方便
  2. 读入存储的时候,读取最小值,并且到自身值为0
  3. Floyd
#include<iostream>
#include<cstring>

using namespace std;
int n,m,k;
const int N = 210;
int d[N][N];

void Floyd()
{
    for(int k = 1; k <= n; k++)
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
}

int main()
{
    cin >> n >> m >> k;
    memset(d,0x3f,sizeof d);
    for(int i = 0; i < m; i++)
    {
        int x,y,c;
        cin >> x >> y >> c;
        d[x][y] = min(d[x][y], c);
        d[x][x] = 0;
        d[y][y] = 0;
    }
    Floyd();
    for(int i = 0; i < k; i++)
    {
        int x,y;
        cin >> x >> y;
        if(d[x][y]>=0x3f3f3f3f/2)
            cout << "impossible" << endl;
        else
            cout << d[x][y] << endl;
    }
    
    return 0;
}

在这里插入图片描述

Prim算法求最小生成树 ✔12.27

原题链接

做题总结
  1. prim算法的思路:选出每个最小边且该节点没有走过。
    关键开辟一个集合存储每个点的所遍历过的最小边的值,(有个前提就是,需要一个点一个点地走,所以有了prim算法)
  2. 自己到自己的距离也应是0x3f,因为d存储的是自己的最短边
  3. 图存储的 都是最小值
#include<iostream>
#include<cstring>

using namespace std;

const int N = 510;
int p[N][N], d[N];
int n, m;
bool st[N];
int res;
int sum;

void prim()
{
    memset(d, 0x3f, sizeof d);
    d[1] = 0;

    for (int k = 0; k < n; k++)
    {
        int t = -1;

        for (int l = 1; l <= n; l++)
        {
            if (st[l] == false && (t == -1 || d[t] > d[l]))
                t = l;
        }
        if (d[t] == 0x3f3f3f3f)
        {
            res++;
            return;
        }
        st[t] = true;
        sum += d[t];
        for (int i = 1; i <= n; i++)
        {
            d[i] = min(d[i], p[t][i]);
        }
    }
}

int main()
{
    memset(p,0x3f,sizeof p);
    cin >> n >> m;
    for (int i = 0; i < m; i++)
    {
        int x, y, c;
        cin >> x >> y >> c;
        p[x][y]= p[y][x] = min(p[x][y],c);
    }
    prim();
    if (res)
        cout << "impossible";
    else
        cout << sum;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/198175.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PMP知识点1

根据PMBOK和参考书籍自己总结的一些不熟悉知识点&#xff0c;当做笔记放这复习。 1. 项目战略管理、组合管理、项目及管理、项目管理区别 战略管理项目组合管理项目集管理项目管理工作内容明确组织战略目标选择有利于实现战略目标的项目分析并利用各项目之间有机联系规范有序…

RAS《Research on Offense and Defense of DDos Based on Evolutionar Game Theory》

Read abstract and personal Summary of《Research on Offense and Defense of DDos Based on Evolutionar Game Theory》Ⅰ&#xff1a;Read abstract(阅读摘要)0&#xff1a;Proper noun interpretation&#xff08;专有名词解释&#xff09;1&#xff1a;The question raise…

windows 休眠后风扇狂转的解决方法

windows 休眠后风扇狂转的解决方法 问题描述&#xff1a; 在Windows电脑接入usb设备后进入休眠状态时&#xff0c;风扇立刻最大功率运行&#xff0c;在拔出usb/唤醒电脑后风扇会恢复正常。 解决方法&#xff1a; 使用powercfg 查询唤醒电脑的设备&#xff0c;然后移除此设备…

C语言基础(五)—— 数组、数组地址(步长+1)、字符串输入输出、随机数

1. 概述在程序设计中&#xff0c;为了方便处理数据把具有相同类型的若干变量按有序形式组织起来——称为数组。数组就是在内存中连续的相同类型的变量空间。同一个数组所有的成员都是相同的数据类型&#xff0c;同时所有的成员在内存中的地址是连续的。数组属于构造数据类型&am…

从Manifold到SNE再到t-SNE再回到Manifold

在介绍t-SNE之前&#xff0c;要从流形开始讲起。 流形Manifold 将流形引入到机器学习领域主要有两个用途&#xff1a; 改进原本欧式空间中的算法&#xff0c;使它能作用到流形上&#xff0c;直接或者间接地利用和流行的性质和构造。将流形映射到欧式空间中&#xff0c;令欧式…

软件测试面试:年后就拿到了5个offer,希望也能助你拿下满意的offer

求职&#xff0c;就像打仗&#xff0c;不仅是一场挑战自己的战斗&#xff0c;也是一场与用人单位的较量。 而求职者只有准备足够充分&#xff0c;才能在这场毫无硝烟的“战场”上取得胜利。 那么软件测试面试需要做哪些准备以及软件测试面试需要哪些技巧呢&#xff1f; 1、熟…

ThreadLocal 适合用在哪些实际生产的场景中?

在通常的业务开发中&#xff0c;ThreadLocal有两种典型的使用场景 场景1&#xff0c;ThreadLocal 用作保存每个线程独享的对象&#xff0c;为每个线程都创建一个副本&#xff0c;这样每个线程都可以修改自己所拥有的副本, 而不会影响其他线程的副本&#xff0c;确保线程安全 …

【内网安全-隧道搭建】内网穿透_Frp上线、测试

目录 Frp&#xff08;简易上线&#xff09; 1、简述&#xff1a; 2、工具&#xff1a; 3、使用&#xff1a; 1、准备&#xff1a; 2、服务端&#xff08;公网&#xff09;&#xff1a; 2、客户端&#xff08;内网&#xff09;&#xff1a; 3、测试方法&#xff1a; 4、…

【Linux】基础IO --- 软硬链接、acm时间、动静态库制作、动静态链接、动静态库加载原理…

我用执着烧死了所有的幼稚和任性&#xff0c;那片荒野慢慢长出了理智冷漠和清醒。 文章目录一、软硬链接1.软硬链接的区别&#xff08;是否具有独立的inode&#xff09;2.软硬链接的作用2.1 软链接作用&#xff08;建立快捷方式&#xff09;2.2 硬链接作用&#xff08;防止误删…

PLC信号处理系列之滤波器设计(MATLAB滤波器设计工具箱介绍)

在学习和应用滤波器解决工程问题之前,需要了解一定的信号处理相关基础知识,有关信号和系统的学习笔记可以参看下面的专栏: https://blog.csdn.net/m0_46143730/article/details/128788864https://blog.csdn.net/m0_46143730/article/details/128788864命令行窗口输入>&g…

排序模型进阶-FTRL

5.8 排序模型进阶-FTRL 学习目标 目标 无应用 无 5.8.1 问题 在实际项目的时候&#xff0c;经常会遇到训练数据非常大导致一些算法实际上不能操作的问题。比如在推荐行业中&#xff0c;因为DSP的请求数据量特别大&#xff0c;一个星期的数据往往有上百G&#xff0c;这种级别…

combit Report Server 28

combit Report Server 28 Added Microsoft SharePoint Online task action.Added support for PostgreSQL 15.Added support for Microsoft SQL Server 2022.Added new option to Microsoft Excel export template. Converting texts starting with “” into Excel formula.Im…

力扣:除自身以外数字的乘积(详解)

前言&#xff1a;本期是关于除自身以外数字的乘积的详解&#xff0c;内容包括四大模块&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读&#xff0c;今天你c了吗&#xff1f; 题目&#xff1a; 给你一个整数数组 nums&#xff0c;返回 数组 ans…

【javaEE】文件

目录 文件概念 文件路径 绝对路径 相对路径 文件类型 文本文件 二进制文件 Java中对文件的操作 对文件系统的操作 get相关方法 文件类型判断和创建 文件删除 文件目录的创建 文件重命名 对文件内容的操作 字符流(操作字符数据) 代码例子 删除文件 复制文件 …

算法刷题-求素数、数据流的中位数、不同的二叉搜索树

求素数、数据流的中位数、不同的二叉搜索树求素数数据流的中位数不同的二叉搜索树求素数 求1-100内的素数&#xff1a; public static void main(String[] args){for(int i0;i<100;i) {checkPrime(i);}}private static void checkPrime(int x){boolean isPrime true;if(x…

nodejs+vue大学生提问论坛系统vscode

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 前端技术&#xff1a;nodejsvueelementui,视图层其实质就是vue页面&#xff0c;通过编写vue页面从而展示在浏览器中&#xff0c;编写完成的vue页面…

Linux-时间和日期、磁盘信息和进程信息

为了方便通过远程终端维护服务器时&#xff0c;查看服务器上当前系统日期和时间 /磁盘空间占用情况/程序执行情况&#xff0c;本节基本都是查询命令时间和日期datecal磁盘和目录空间dfdu进程信息pstopkill1.时间和日期序号命令作用01cal查看一个月日历&#xff0c; -y选项可以查…

consul集群解决单注册弊端

consul集群前面我们用consul注册发现服务&#xff0c;这里的弊端显而易见&#xff0c;单机版如果挂掉&#xff0c;就无法正常使用。consul的集群是复制模式&#xff0c;每个节点的信息一致。当其中一个挂掉&#xff0c;其他正常运行。consul官网建议最好是3个节点&#xff0c;其…

MyEclipse安装及需要进行的配置

安装&#xff1a;https://blog.csdn.net/qq_30764991/article/details/82531415?spm1001.2101.3001.6650.9&utm_mediumdistribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-9-82531415-blog-126523828.pc_relevant_aa2&depth_1-utm_sou…

网络游戏与未来生存——谈一下不要因为认知不到位让孩子失去未来的机会

这个话题要从几个月前的一个事件谈起&#xff0c;先看看下面的截图&#xff1a;于是&#xff0c;那一天&#xff0c;各种阴谋论甚嚣尘上&#xff0c;大多数的话题都是直指腾讯&#xff0c;说腾讯的活动能力太强了。随后几天网上也是各种关于网络游戏毁掉孩子未来的说法和观点&a…