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

P3956 [NOIP2017 普及组] 棋盘

时间:2023-10-02 15:56:25浏览次数:40  
标签:NOIP2017 int 边权 first dijkstra tot 棋盘 P3956 dis

传送门 P3956 [NOIP2017 普及组] 棋盘

不清楚曾师为什么把这个神奇的题目放在搜索 \(search\) 专栏,反正我用 \(dijkstra\) 水过去了,虽然 \(dijkstra\) 严格来说也是一种能够解决一般性最短路问题的算法。

然后考虑这道题的建图。这道题来看首先是去除魔法的部分,一般地,任意一个点只能到与它欧拉距离为 \(1\) 的四个点上。二这四个点分为两种考虑。第一种情况是两点之间的颜色相同,那么它们的边权即为 \(0\) ,否则两点之间的边权为 \(1\)。

其次考虑有魔法的情况。因为获取到了魔法,所以一个点周围的一圈得以再扩展一周,而若两点颜色相同边权为 \(2\) ,否则边权为 \(3\) 。

有了这个之后直接暴力建图即可。然而这样跑 \(dijkstra\) 只能拿到 \(50pts\) 。

因为需要考虑终点没有颜色的情况,所以针对没有颜色的终点加一个建图的特判即可。

然后直接用 \(dijkstra\) 在建图的基础上跑一遍就好了。

之后呢直接输出 \(calc(\{m,m\})\) 就是答案了。

要注意的是边的内存大小一定要开成 \(12\times n\),否则各种 \(RE\).

代码的话我直接挂在底下就好了。完事。

#include <bits/stdc++.h>   
#define Register register
#define ed calc({m,m})
using namespace std ;
const int N=1e5+100,M=1e7+1000,INF=0x3f3f3f3f,P=105;
int st,n,m,tot;
int first[N],nex[M],to[M],w[M];
int dis[N];
bool vis[N];int mp[105][105]; 
priority_queue<pair<int,int> >q; 
void add(int x,int y,int z){
	nex[++tot]=first[x];
	first[x]=tot;
	to[tot]=y;
	w[tot]=z;
}
void dijkstra(void){
	memset(dis,INF,sizeof dis );
	dis[st] = 0;
	q.push(make_pair(0,st));
	while(!q.empty()){
		int u=q.top().second;
		q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		for(int e=first[u];e;e=nex[e]){
			int v=to[e];
			if(dis[v]>dis[u]+w[e]){
				dis[v]=dis[u]+w[e];
				q.push(make_pair(-dis[v],v));
			}
		}
	}
}
int calc(pair<int,int> alpha){
	return alpha.first*P+alpha.second;
}
int main(){
	cin>>m>>n;
	for(Register int i=1;i<=n;++i){
		int x,y,z;
		cin>>x>>y>>z;
		mp[x][y]=z+1;
	}
	for(register int i=1;i<=m;++i)
		for(register int j=1;j<=m;++j){
			int x=i,y=j;
			if(mp[x][y]){
				if(mp[x+1][y])add(calc({x,y}),calc({x+1,y}),(mp[x][y]==mp[x+1][y]?0:1));
				if(mp[x-1][y])add(calc({x,y}),calc({x-1,y}),(mp[x][y]==mp[x-1][y]?0:1));
				if(mp[x][y+1])add(calc({x,y}),calc({x,y+1}),(mp[x][y]==mp[x][y+1]?0:1));
				if(mp[x][y-1])add(calc({x,y}),calc({x,y-1}),(mp[x][y]==mp[x][y-1]?0:1));
				if(mp[x+1][y+1])add(calc({x,y}),calc({x+1,y+1}),(mp[x][y]==mp[x+1][y+1]?2:3));
				if(mp[x-1][y+1])add(calc({x,y}),calc({x-1,y+1}),(mp[x][y]==mp[x-1][y+1]?2:3));
				if(mp[x+1][y-1])add(calc({x,y}),calc({x+1,y-1}),(mp[x][y]==mp[x+1][y-1]?2:3));
				if(mp[x-1][y-1])add(calc({x,y}),calc({x-1,y-1}),(mp[x][y]==mp[x-1][y-1]?2:3));
				if(mp[x+2][y])add(calc({x,y}),calc({x+2,y}),(mp[x][y]==mp[x+2][y]?2:3));
				if(mp[x][y+2])add(calc({x,y}),calc({x,y+2}),(mp[x][y]==mp[x][y+2]?2:3));
				if(mp[x][y-2])add(calc({x,y}),calc({x,y-2}),(mp[x][y]==mp[x][y-2]?2:3));
				if(mp[x-2][y])add(calc({x,y}),calc({x-2,y}),(mp[x][y]==mp[x-2][y]?2:3));
			}
			if(calc({x+1,y})==ed) add(calc({x,y}),ed,2);
			if(calc({x-1,y})==ed) add(calc({x,y}),ed,2);
			if(calc({x,y+1})==ed) add(calc({x,y}),ed,2);
			if(calc({x,y-1})==ed) add(calc({x,y}),ed,2);
		} 
	st=calc({1,1});
	dijkstra();
	if(dis[calc({m,m})]==INF){
		puts("-1");
		return 0;
	}
	cout<<dis[calc({m,m})];
}

标签:NOIP2017,int,边权,first,dijkstra,tot,棋盘,P3956,dis
From: https://www.cnblogs.com/qxblog/p/P3956_search.html

相关文章

  • 软件测试|使用Python打印五子棋棋盘
    简介五子棋是我们传统的益智类游戏,在制作五子棋时,我们需要先将棋盘打印出来,本文就来介绍一下使用Python打印五子棋棋盘。步骤一:打印空棋盘首先,我们需要在Python中定义一个棋盘函数,该函数将打印一个空棋盘。下面是代码示例:defprint_board():foriinrange(15):forji......
  • 66-综合练习-绘制不同颜色的多个同心圆-绘制棋盘
             ......
  • NOIP2017提高组初赛易错题解析
     8.由四个不同的点构成的简单无向连通图的个数是()A.32 B.35 C.38 D.41错误原因:数重了正解:分情况计算,6条边的有1种,5条边的有C(6,1)=6种,4条边的有C(6,4)=15种,3条边,要分度数,2+2+1+1的有12种,3+1+1+1的有4种,共38种 10.若 f0​=0,f1​=1,fn+1​=(fn​+fn−1)/2​​,则随着......
  • 「NOIP2017 普及组」棋盘 题解
    前言一个绿题,风光啊QwQ题面传送门思路怎么走我们定义一个函数dfs(x,y,coin,can,color)x,y表示坐标,coin表示当前的金币数量,color表示当前坐标的颜色,can表示当前是否能施展魔法。再加一个mp数组记录颜色,-1表示无颜色,0表示红色,1表示黄色为什么不直接使用mp[x][y]获取颜......
  • 第14周项目5体会棋盘游戏中的数据储存
    问题及代码:/**Copyright(c)2014,烟台大学计算机学院*Allrightsreserved.*文件名称:MADE67.cpp*作者:孙化龙*完成日期:2014年12月2日*版本号:v1.0**问题描述:定义一个8行8列的二维数组a[8][8]。为二维数组中的数据赋50以内的随机数;设计函数out()、outDiagona......
  • 棋盘移动
    #include<iostream>usingnamespacestd;inta(intn){if(n==4){cout<<"4,5-->9,10"<<endl;cout<<"8,9-->4,5"<<endl;cout<<"2,3->8,9"<<endl;cout<<&q......
  • 基于生长的棋盘格角点检测方法--(1)原理介绍
    前言棋盘格中角点检测方法是相机标定中必不可少的步骤之一。Opencv中的函数boolfindChessboardCorners(InputArrayimage,SizepatternSize,OutputArraycorners,intflags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE)就可以轻松实现棋盘格角点检测结果。如下图所示......
  • 基于生长的棋盘格角点检测方法--(2)代码详解(上)
    上一篇介绍了基于生长的棋盘格角点检测方法的大概原理,详见:基于生长的棋盘格角点检测方法–(1)原理介绍本文进一步从代码解读角度出发,更深入地理解工程中是如何实现的。本文中用到的代码可以从以下链接下载http://www.cvlibs.net/software/libcbdetect/这里我把代码中主要的函......
  • 基于生长的棋盘格角点检测方法--(3)代码详解(下)
    接着上一篇基于生长的棋盘格角点检测方法–(2)代码详解(上),来看一下第二个重要函数chessboardsFromCorners。该函数的目的是用上一步骤中找到的角点恢复出棋盘结构。首先初始化一个3x3的角点矩阵,也就是一个2x2的棋盘格,这是组成一个棋盘的最小单位了。然后利用定义的棋盘能量函数来从......
  • 一个简单棋盘覆盖定理的证明
    能够用\(1\timesl\)的矩形覆盖\(n\timesm\)棋盘的充要条件是\(l\midn\lorl\midm\)。充分性显然,考虑证明必要性。为了方便,我们将行和列记为\(0\simn-1\)和\(0\simm-1\)。考虑设\((i,j)\)的权值为\(\omega_{l}^{i+j}\),一个\(1\timesl\)的矩形覆盖的区域显然......