首页 > 其他分享 >P3956 [NOIP2017 普及组] 棋盘

P3956 [NOIP2017 普及组] 棋盘

时间:2024-04-14 15:33:41浏览次数:31  
标签:NOIP2017 棋盘 dist int include flag bool now P3956


/*
    这题本身不难, 但是我写难了
    就是一个bfs, 没了
    但是我的写法恰好犯了一个错误
    hark数据
    3 5
    1 1 0
    2 1 1
    3 1 1
    2 2 0
    3 3 0
    答案是4而我能输出3
     0 -1 -1 
     1  0 -1 
     1 -1  0 
    原因是 我先走到了(2, 2)这时候到(3, 2)的花费最小是4, 我还加入了队列, 这时候的上一个颜色是0, 这个记为a
    然后, 我后面又走到了(3, 1)从这个到(3, 2) 更新了最小花费为3, 我也加入了队列, 这时候的上一个颜色是1, 这个记为b
    但是前面花费是4的时候我加入了队列(a), 上一个颜色是0, 导致走到(3, 3)时上个颜色是0 和 (3, 3)的0相等不花费
    就把到(3, 3)的最小花费变成了3, 就错了, 
    使用优先队列, 用到每个点的最小距离排, 就可以解决这个问题, 就可以先算b, 把正确答案算出来
    
    这里说一下优先队列的结构体排序
    众所周知优先队列默认是大根堆
    是从大到小排, 但是是用的小于号, 这时候直接重载小于号像下面就行了, 不用更换模式
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 1100, M = 110;

int g[M][M];
int n, m;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
// bool st[M][M];
int dist[M][M];

struct Node
{
    int sum;
    int x, y;
    bool flag; // 到这一步是否使用了魔法
    int now; // now是当前的颜色, 因为不能更改嘛, 用这个记录一下这次的颜色
    bool operator< (const Node &W)const
    {
        return sum < W.sum;
    }
};

int bfs()
{
    memset(dist, 0x3f, sizeof dist);
    priority_queue<Node> q;
    q.push({0, 1, 1, 0, g[1][1]});
    dist[1][1] = 0;
    
    while (q.size())
    {
        auto t = q.top();
        q.pop();
        
        int x = t.x, y = t.y, now = t.now;
        bool flag = t.flag;
        
        for (int i = 0; i < 4; i ++ )
        {
            int a = x + dx[i], b = y + dy[i], s = 0; // s是这次走的花费
            if (a < 1 || b < 1 || a > n || b > n) continue;
            if (g[a][b] != now) // 如果颜色不同
            {
                if (g[a][b] >= 0) s = 1; // 这个点有颜色
                else if (!flag) s = 2; // 没颜色且之前没用过魔法
                else continue; // 说明已经到不了了
            }
            
            if (dist[a][b] > dist[x][y] + s)
            {
                dist[a][b] = dist[x][y] + s;
                // if (a == 4 && b == 4) cout << x << ' ' << y << ' ' << now << endl;
                // cout << a << ' ' << b << endl;
                q.push({dist[a][b], a, b, s == 2, s == 2 ? now : g[a][b]}); // 这段话可以细品 s == 2 ? now : g[a][b]是如果使用了魔法, 那么这个点的颜色就是上个点的颜色, 没有的话就是它自身的颜色
            }
        }
    }
    
    return dist[n][n];
}

int main()
{
    memset(g, -1, sizeof g);
    cin >> n >> m;
    while (m -- )
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = c + 6;
    }
    // for (int i = 1; i <= n; i ++ )
    // {
    //     for (int j = 1; j <= n; j ++ )
    //         printf("%2d ", g[i][j]);
    //     puts("");
    // }
            
    int t = bfs();
    if (t != 0x3f3f3f3f) cout << t;
    else cout << -1;
    
    return 0;
}


// 错误的写法

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

using namespace std;

const int N = 1100, M = 110;

int g[M][M];
int n, m;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
// bool st[M][M];
int dist[M][M];

struct Node
{
    int x, y;
    bool flag;
    int now;
};

int bfs()
{
    memset(dist, 0x3f, sizeof dist);
    queue<Node> q;
    q.push({1, 1, 0, g[1][1]});
    dist[1][1] = 0;
    
    while (q.size())
    {
        auto t = q.front();
        q.pop();
        
        int x = t.x, y = t.y, now = t.now;
        bool flag = t.flag;
        
        for (int i = 0; i < 4; i ++ )
        {
            int a = x + dx[i], b = y + dy[i], s = 0;
            if (a < 1 || b < 1 || a > n || b > n) continue;
            if (g[a][b] != now)
            {
                if (g[a][b] >= 0) s = 1;
                else if (!flag) s = 2;
                else continue; // 说明已经到不了了
            }
            
            if (dist[a][b] > dist[x][y] + s)
            {
                dist[a][b] = dist[x][y] + s;
                if (a == 4 && b == 4) printf("%d %d %d %d %d %d\n", x, y, s, g[a][b], g[x][y], now);
                // cout << a << ' ' << b << endl;
                q.push({a, b, s == 2, (s == 2) ? now : g[a][b]});
            }
        }
    }
    
    return dist[n][n];
}

int main()
{
    memset(g, -1, sizeof g);
    cin >> n >> m;
    while (m -- )
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = c;
    }
    
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= n; j ++ )
            printf("%2d ", g[i][j]);
        puts("");
    }
            
    int t = bfs();
    if (t != 0x3f3f3f3f) cout << t;
    else cout << -1;
    
    return 0;
}

标签:NOIP2017,棋盘,dist,int,include,flag,bool,now,P3956
From: https://www.cnblogs.com/blind5883/p/18134200

相关文章

  • [题解] <NOIP2017> 时间复杂度
    [题解]NOIP2017时间复杂度题目描述小明正在学习一种新的编程语言A++,刚学会循环语句的他激动地写了好多程序并给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序,于是你的机会来啦!下面请你编写程序来判断小明对他的每个程序给出的时间复杂度是否正......
  • 棋盘进行黑白染色(java)
    【题目】 有一个n*m的棋盘,现在对这个棋盘进行黑白染色,左上角染成黑色。从左上角开始,每个黑色格的相邻格染成白色,白色格的相邻格染成黑色。以下给出了一个5*7的棋盘的染色示例。给定n和m,请问棋盘上一共有多少方格被染成了黑色。【代码】publicclassTest13{public......
  • P3956 [NOIP2017 普及组] 棋盘
    原题链接题解dijkstra算法的应用。相同颜色权值为0;不同颜色权值为1;有颜色到无颜色权值为2。其中不能连续两步走无颜色结点,即该情况需要特别考虑。code #include<bits/stdc++.h>usingnamespacestd;constintMAX=1e9;inta[105][105],dis[105][105],vis[105][105];int......
  • 2023年蓝桥杯省赛——棋盘
    目录题目链接:10.棋盘-蓝桥云课(lanqiao.cn)思路我的直接暴力思路代码实现前缀和思路前缀和:更多举例差分数组:更多举例前缀和与差分数组的关系如下代码实现 总结题目链接:10.棋盘-蓝桥云课(lanqiao.cn)思路我的直接暴力思路        我的这段Ja......
  • 2733: 【搜索】【广度优先】 马遍历棋盘
    题目描述有一个n*m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步输入一行四个数据,棋盘的大小和马的坐标输出一个n*m的矩阵,代表马到达某个点最少要走几步(左对齐,宽5格,不能到达则输出-1)样例输入4411样例输出0325......
  • [NOIP2017 提高组] 小凯的疑惑 / [蓝桥杯 2013 省] 买不到的数目
    这肯定是学证明了,看这篇文章补充一下细节首先,\(m\)的范围应该是\([0,b-1]\)然后,当\(m\)取不同值的时候,\(ma\)%\(b\)一定为不同值(这个性质确实有点奇特,可以记下来)反证,如果\(m_1a\equivm_2a\:(mod\:b)\)且\(0≤m_1<m_2≤b-1\),那么就有\(b|(m_2-m_1)a\),题目给出了\(a,b\)互质,......
  • P3957 [NOIP2017 普及组] 跳房子
    原题链接题解二分加动态维护区间最大值注意设立变量的含义,改变变量值的规则code#include<bits/stdc++.h>#definelllonglongusingnamespacestd;llsum[500005]={0};structunit{llx,v;booloperator<(constunit&b)const{returnb.v>v;}//}room[5000......
  • P3958 [NOIP2017 提高组] 奶酪
    原题链接思路并查集然后看看是否存在上表面联通的洞与下表面联通的洞位于同一集合code#include<bits/stdc++.h>usingnamespacestd;doublen,h,r;intfa[1005];vector<int>up,down;struct{doublex,y,z;}hole[1005];doubledis(inti,intj){returnpo......
  • P3957 [NOIP2017 普及组] 跳房子
    50分代码1//P3957[NOIP2017普及组]跳房子2#include<iostream>3#include<queue>4#include<cstring>5#include<cmath>6usingnamespacestd;7typedeflonglongll;8intn,d,k;9inta[500010][2];10llf[500010],sum=0;11boo......
  • 小Q的棋盘
    我们先按树形DP做我们模拟一下如何走,会发现有可能会先从根节点往下走,然后回到根节点,再从根节点继续往下走,这个过程甚至可以重复多次所以我们会发现很重要的一点就是是否回到根节点,所以我们设\(f[i][j][0/1]\)表示根节点是\(i\),走\(j\)步,终点是不是根节点的最多走的点数(注意这里......