蓝桥杯31天冲刺打卡(Day21)

目录

A 最短路

解析:

代码:

B 修改数组

解析:

代码:




 

解析:

这是一道最短路问题,可以用迪杰斯特拉、bellford、floyd来做,不过由于这是一道填空题,没必要浪费太多时间,并且用肉眼看便能得出答案(6)。(以下代码非博主手写,都是从网上找回来的,便于读者学习最短路)

代码:

迪杰斯特拉

#include <iostream>
#include <cstring>
using namespace std;
const int N=200,n=19;
int dist[N];
int g[N][N];
void add(char x,char y,int c)
{
  int a=x-'A'+1;
  int b=y-'A'+1;
  g[a][b]=g[b][a]=c;
}
bool vis[N];
int dijkstra()
{
  memset(dist,0x3f,sizeof dist);
  dist[1]=0;
  for(int i=0;i<n;i++)
  {
    int t=-1;
    for(int j=1;j<=n;j++)
    {
      if(!vis[j]&&(t==-1||dist[j]<dist[t]))
        t=j;
    }
    vis[t]=1;

    for(int j=1;j<=n;j++)
    {
      dist[j]=min(dist[j],dist[t]+g[t][j]);
    }
  }
  return dist[n];
}
int main()
{
    memset(g,0x3f,sizeof g);
    add('A','B',2);
    add('A','C',1);
    add('A','D',1);
    add('A','D',1);
    add('B','J',2);
    add('B','G',1);
    add('C','D',3);
    add('C','F',3);
    add('C','G',3);
    add('D','E',1);
    add('D','G',2);
    add('D','H',1);
    add('D','I',2);
    add('E','H',1);
    add('E','I',3);
    add('F','G',1);
    add('F','J',1);
    add('G','F',1);
    add('G','I',3);
    add('G','K',2);
    add('H','I',1);
    add('H','L',2);
    add('I','M',3);
    add('J','S',2);
    add('K','N',1);
    add('K','L',3);
    add('K','P',2);
    add('L','M',1);
    add('L','R',1);
    add('M','N',2);
    add('M','Q',1);
    add('M','S',1);
    add('N','P',1);
    add('O','P',1);
    add('O','Q',1);
    add('O','R',3);
    add('R','S',1);
    cout<<dijkstra();
  return 0;
}

floyd

#include <iostream>
#include <vector>
#define INF 0x3f3f3f3f
using namespace std;
const int n = 20;
int g[n][n];
int main()
{
  for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= n; j ++ )
            if (i == j) g[i][j] = 0;
            else g[i][j] = INF;
  g[1][3] = 1;
  g[3][1] = 1;
  g[1][2] = 2;
  g[2][1] = 2;
  g[1][4] = 1;
  g[4][1] = 1;
  g[1][5] = 1;
  g[5][1] = 1;
  g[2][7] = 1;
  g[7][2] = 1;
  g[2][10] = 2;
  g[10][2] = 2;
  g[3][4] = 3;
  g[4][3] = 3;
  g[3][7] = 3;
  g[7][3] = 3;
  g[3][6] = 3;
  g[6][3] = 3;
  g[4][7] = 2;
  g[7][4] = 2;
  g[4][5] = 1;
  g[5][4] = 1;
  g[4][8] = 1;
  g[8][4] = 1;
  g[4][9] = 2;
  g[9][4] = 2;
  g[5][8] = 1;
  g[8][5] = 1;
  g[5][9] = 3;
  g[9][5] = 3;
  g[6][7] = 1;
  g[7][6] = 1;
  g[6][10] = 1;
  g[10][6] = 1;
  g[7][9] = 3;
  g[9][7] = 3;
  g[7][11] = 2;
  g[11][7] = 2;
  g[8][9] = 1;
  g[9][8] = 1;
  g[8][12] = 2;
  g[12][8] = 2;
  g[9][13] = 3;
  g[13][9] = 3;
  g[10][19] = 2;
  g[19][10] = 2;
  g[11][17] = 2;
  g[17][11] = 2;
  g[11][12] = 3;
  g[12][11] = 3;
  g[11][14] = 1;
  g[14][11] = 1;
  g[12][18] = 1;
  g[18][12] = 1;
  g[12][13] = 1;
  g[13][12] = 1;
  g[13][14] = 2;
  g[14][13] = 2;
  g[13][16] = 1;
  g[16][13] = 1;
  g[13][19] = 1;
  g[19][13] = 1;
  g[14][17] = 1;
  g[17][14] = 1;
  g[15][16] = 1;
  g[16][15] = 1;
  g[15][17] = 1;
  g[17][15] = 1;
  g[15][18] = 3;
  g[18][15] = 3;
  g[18][19] = 1;
  g[19][18] = 1;
  // C++ Version
 //floyd板子 
for (int k = 1; k <= n; k++) {
  for (int x = 1; x <= n; x++) {
    for (int y = 1; y <= n; y++) {
      g[x][y] = min(g[x][y], g[x][k] + g[k][y]);
    }
  }
}
  cout << g[1][19] << "\n";
  return 0;
}

B 修改数组

 

 

前情:

        这道题博主试了一下暴力,结果有80分和90分,那么它们的区别在哪呢?

        上面的代码80分,下面的90分。为什么呢?我们可以看到上面的是用cin输入以及用bool来标记,而下面是用scanf和int来判定。众所周知,cin读取的速度是比scanf慢的,至于慢多少我也不知道,不过我想告诉大家的是:这道题必须得用scanf和int声明的数组才可以得90分。我试过单用scanf一样是80分,单用int声明的数组也是80分,用cin或bool数组依旧是80分,只有用int声明的数组+scanf才是90分,这说明什么?告诫我们没事多用scanf和int声明的数组,少用cin和bool。

#include <bits/stdc++.h>//80
using namespace std;
const int maxn=1e6+10;
bool vis[maxn];
int main() {
	int n,a;
	cin>>n;
	for(int i=0; i<n; i++) {
		cin>>a;
		while(vis[a]) a++;
		cout<<a<<' ';
		vis[a]=true;
	}
	return 0;
}
#include <bits/stdc++.h>//90
using namespace std;
int vis[1000005];
int main() {
	int n,a;
	scanf("%d",&n);
	for(int i=0; i<n; i++) {
		scanf("%d",&a);
		while(vis[a]) a++;
		cout<<a<<' ';
		vis[a]=1;
	}
	return 0;
}

解析:

        这是一道并查集的题目。怎么想到是并查集的呢?我们由暴力可以得出,只要该数用过就标记,然后往后继续遍历查找未用过的数,这样做的话复杂度平均是O(n^2),最坏高达O(n^2logn),无疑必爆,可是蓝桥官网居然有90分(不能理解,不过这告诉我们这还是个暴力杯)。由于这道题可以看作若干个集合,大家都知道集合是互异性,所以如果重复出现的需要一直+1,直到未曾用过。又因为并查集是将每个数组初始化为i,然后find是找根节点,这样我们可以将已经用过的点压到子节点里,更新根节点,所以只要对已用的集合+1并压入子节点就行了。

        这一种并查集是没有初始化的,下面那种并查集是初始化的了(!!!注意注意:下面初始化并查集时,不要只初始到n,不见得题目给出的数值就一定是n以内,博主就是卡死在了n这里

代码:

#include <bits/stdc++.h>
using namespace std;
int p[100005],n;

int find(int x) {
	return p[x]==0 ? x : p[x]=find(p[x]); 
}


int main() {
	cin>>n;
	for(int i=1; i<=n; i++) {
		int a;
		cin>>a;
		int x=find(a);
		p[x]=x+1; 
		cout<<x<<" ";
	}
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
int p[1000010],n;

void init() {
    for(int i=1; i<=1000005; i++)
    p[i]=i;
}

int find(int x) {
    return p[x]==x ? x : p[x]=find(p[x]); 
}


int main() {
    cin>>n;
    init();
    for(int i=1; i<=n; i++) {
        int a;
        cin>>a;
        int x=find(a);
        p[x]=x+1; 
        cout<<x<<" ";
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_谦言万语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值