传送门: [NOIP2017 普及组] 棋盘 - 洛谷
思路: 将棋盘的每一个格子看做一个点,建一个无向图用来跑最短路.
这道题本应用搜索来做,但是转换成最短路好像简单点
建图:
1.对于已经有颜色的格子,在扫描四个方向的格子对相同颜色的建条长度为0的边,不同颜色的建条长度为1的边
2.对于没有颜色的格子,对于四个方向所有有颜色的格子都要先建条长度为2的边,再在四周有颜色格子之间两两建边,颜色相同就建长度为2的边,颜色不同就建长度为3的边,如下图所示一个没有颜色的格子四周格子的边
建好边就可以跑spfa了,但是这个做法只有90分
90分(满分100)的代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> PII;
const double PI=3.1415926535;
const int N=1e6+10;
bool st[N];
int d[110][110];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1
};
int e[N],ne[N],w[N],h[N],idx;
int dist[N];
int n,m;
void add(int a,int b,int c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void spfa()
{
memset(dist,0x3f,sizeof dist);
dist[m+1]=0;
queue<int>que;
que.push(m+1);
while(que.size())
{
int t=que.front();
que.pop();
st[t]=false;
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
if(!st[j])
{
st[j]=true;
que.push(j);
}
}
}
}
}
signed main()
{
memset(h,-1,sizeof h);
scanf("%lld%lld",&m,&n);
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
d[i][j]=-1;
for(int i=1;i<=n;i++)
{
int x,y,c;
scanf("%lld%lld%lld",&x,&y,&c);
d[x][y]=c;
}
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
{
if(d[i][j]!=-1)
{
for(int k=0;k<4;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(x<=0||x>m||y<=0||y>m)
continue;
if(d[x][y]!=-1)
{
if(d[x][y]==d[i][j])
{
add(x*m+y,i*m+j,0);
}else{
add(x*m+y,i*m+j,1);
}
}
}
}else{
vector<PII>v;
for(int k=0;k<4;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(x<=0||x>m||y<=0||y>m)
continue;
if(d[x][y]!=-1)
v.push_back({x*m+y,d[x][y]});
add(x*m+y,i*m+j,2);
add(i*m+j,x*m+y,2);
}
if(v.size()>1)
{
for(int i=0;i<v.size();i++)
for(int j=0;j<v.size();j++)
{
if(i==j)
continue;
if(v[i].second!=v[j].second)
{
add(v[i].first,v[j].first,3);
add(v[j].first,v[i].first,3);
}else{
add(v[j].first,v[i].first,2);
add(v[i].first,v[j].first,2);
}
}
}
}
}
spfa();
if(dist[m*m+m]>=1e9)
puts("-1");
else
cout<<dist[m*m+m];
return 0;
}
还有,同样是转换成无向图建边的大佬的满分代码
题解 P3956 【棋盘】 - 恨妹不成穹 的博客 - 洛谷博客
题目中n的范围是1~1000,实际最多也就1000个点,所以可以使用dijkstra,
至于更加详细的建边过程在大佬博客里面
代码:
#include<bits/stdc++.h>
using namespace std;
bool f[1002];
int n,m,x[1002],y[1002],z[1002][1002],col[1002],sta,en,flag,s[1002];
void dj(int k)
{
s[k]=0;
int maxn,t;
for(int i=1;i<=m;i++)
{
maxn=99999999;
for(int j=1;j<=m;j++)
{
if(f[j]==0&&s[j]<maxn)
{
maxn=s[j];
t=j;
}
}
f[t]=1;
for(int j=1;j<=m;j++)
{
s[j]=min(s[t]+z[t][j],s[j]);
}
}
}
int main()
{
//freopen("chess.in","r",stdin);
//freopen("chess.out","w",stdout);
memset(z,1,sizeof(z));
memset(s,1,sizeof(s));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x[i],&y[i],&col[i]);
if(x[i]==1&&y[i]==1)
{
sta=i;
}
if(x[i]==n&&y[i]==n)
{
flag=1;
en=i;
}
}
if(flag==0)
{
en=m+1;
x[en]=y[en]=n;
}
for(int i=1;i<m;i++)
{
for(int j=i+1;j<=m;j++)
{
if(abs(x[i]-x[j])+abs(y[i]-y[j])==1)
{
z[i][j]=z[j][i]=abs(col[i]-col[j]);
}
if(abs(x[i]-x[j])+abs(y[i]-y[j])==2)
z[i][j]=z[j][i]=2+abs(col[i]-col[j]);
}
}
if(flag==0)
{
for(int i=1;i<=m;i++)
{
if(abs(x[i]-x[en])+abs(y[i]-y[en])==1)
{
z[i][en]=z[en][i]=2;
}
}
m++;
}
dj(sta);
if(s[en]<16843009)
cout<<s[en];
else
cout<<-1;
return 0;
}