P3956 [NOIP2017 普及组] 棋盘

发布时间 2023-10-02 15:53:03作者: q(x)

传送门 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})];
}