双指针,BFS和图论(蓝桥)

双指针,BFS和图论

1.日志统计

题意:

每一篇日志有俩个属性时间ts和编号id。如果在长度为D的时间段内收到不少于K个赞,就是热帖。求特贴的数目。

思路:

有俩种思路:1.先遍历帖子,再遍历时间段, 2.先遍历时间段,再遍历帖子。但是这俩种暴力都会超时。所以需要优化,可以发现先遍历时间段再遍历帖子的算法,第二重循环会有一段重复的部分,因此可以优化。同时记录俩端的指针,当时间段长于D的时候,就将前面一个帖子数减去1。

代码:

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

using namespace std;
const int N=100010;

#define x first
#define y second

typedef pair<int,int> PII;
PII logs[N];
bool st[N];
int cnt[N];

int main()
{
    int n,d,k;
    scanf("%d%d%d",&n,&d,&k);
    for(int i=0;i<n;i++) scanf("%d%d",&logs[i].x,&logs[i].y);
    sort(logs,logs+n);
    
    for(int i=0,j=0;i<n;i++)
    {
        int id=logs[i].y;
        cnt[id]++;
        while(logs[i].x-logs[j].x>=d) 
        {
            cnt[logs[j].y]--;
            j++;
        }
        if(cnt[id]>=k) st[id]=true;
        
    }
    
    for(int i=0;i<N;i++)
        if(st[i])
            printf("%d\n",i);
    
    
    return 0;
}

2.献给阿尔吉侬的花束

题意:

在给定的二维矩阵中找一条可行的最短路径,求最短路径是多少,如果没有,输出oop!

第一行是一个正整数 T,表示一共有 T 组数据。

每一组数据的第一行包含了两个用空格分开的正整数 R 和 C,表示地图是一个 R×C 的矩阵。

思路:

这道题就是一道简单的宽搜题,宽搜题需要定义

1.一个存储地图的二维数组

2.一个判断是否已经走过的st数组(如果需要求距离,可以用dist替代)

3.一个队列,可以用c++的也可以用数组模拟

本题每次更新距离之后,判断一下该点是否是重点,是最快结束的。

代码:

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

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 210;

int n, m;
char g[N][N];
int dist[N][N];

int bfs(PII start, PII end)
{
    queue<PII> q;
    memset(dist, -1, sizeof dist);

    dist[start.x][start.y] = 0;
    q.push(start);

    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

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

        for (int i = 0; i < 4; i ++ )
        {
            int x = t.x + dx[i], y = t.y + dy[i];
            if (x < 0 || x >= n || y < 0 || y >= m) continue;  // 出界
            if (g[x][y] == '#') continue;  // 障碍物
            if (dist[x][y] != -1) continue;  // 之前已经遍历过

            dist[x][y] = dist[t.x][t.y] + 1;

            if (end == make_pair(x, y)) return dist[x][y];

            q.push({x, y});
        }
    }

    return -1;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T -- )
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);

        PII start, end;
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (g[i][j] == 'S') start = {i, j};
                else if (g[i][j] == 'E') end = {i, j};

        int distance = bfs(start, end);
        if (distance == -1) puts("oop!");
        else printf("%d\n", distance);
    }

    return 0;
}

3.交换瓶子

题意:

有 N个瓶子,编号 1∼N,放在架子上。要求每次拿起 2 个瓶子,交换它们的位置。

经过若干次后,使得瓶子的序号从小到大排列。如;

瓶子:2 1 3 5 4 
-------->
位置:1 2 3 4 5

求最少要交换多少次?

思路:

本题思路比较精巧,是个图论和环的题目。可以将每个瓶子看成点,向瓶子应该在的位置的瓶子连边,构成环。

做交换:

交换一:环内的点交换—>每次将环列成俩个

交换二: 环之间的点交换–>每次合并俩个环

由于最后要得到的情况是每个点都和自己连城一个环,所有最后有n个环,最少要做n-k次交换,k环的个数。题目就转化为了求环的个数。

代码:

#include <iostream>
#include <algorithm>

using namespace std;
const int N=10010;

int b[N];
bool st[N];

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>b[i];
    
    int cnt=0;
    for(int i=1;i<=n;i++)
        if(!st[i])
        {
            cnt++;
            for(int j=i;!st[j];j=b[j])
                st[j]=true;
        }
        
    cout<<n-cnt<<endl;
    return 0;
}
发布了75 篇原创文章 · 获赞 8 · 访问量 1256

猜你喜欢

转载自blog.csdn.net/qq_40905284/article/details/104934119