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