题目大意:
给你一个n(n<=200)个点,m(m<=n*n)的有向图,然后每条边都有一个颜色,然后要求求出1->n的一条最短路径,满足相邻的两条边不能是同一种颜色。输出最短路径长度。
解题思路:
一道很水的SPFA题目,只是要加上一点限制条件,我们可以用dist[ i ][ j ]表示第i个点并且是由j颜色的边连过来的最短路,一开始我们将所有的赋初始值为无穷大,然后令dist[1][0]=0,接着就是SPFA跑一遍就行了。
需要注意的是,这个图由自环,我们可能有时要通过自环来改变颜色,所以自环不能去除。
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define MIN(a,b) ((a)>(b)?(b):(a))
using namespace std;
struct bian_
{
int num;
int color;
int next;
}bian[40010]={{0,0,0}};
int First[210]={0};
int n,m;
int dui[700010]={0};
int duip=0;
int dist[210][4]={{0}};
int hash[210]={0};
inline void Add(int p,int q,int r,int k)
{
bian[k].num=q;
bian[k].color=r;
bian[k].next=First[p];
First[p]=k;
return;
}
inline void SPFA()
{
memset(dist,0x3f3f3f3f,sizeof(dist));
dui[++duip]=1;
dist[1][0]=0;
for(int i=1;i<=duip;i++)
{
int u=dui[i];
hash[u]=0;
dui[i]=0;
for(int p=First[u];p!=0;p=bian[p].next)
{
int flag=0;
int v=bian[p].num;
int C=bian[p].color;
if(dist[v][C]>dist[u][0]+1)
{
dist[v][C]=dist[u][0]+1;
flag=1;
}
if(C!=1 && dist[v][C]>dist[u][1]+1)
{
dist[v][C]=dist[u][1]+1;
flag=1;
}
if(C!=2 && dist[v][C]>dist[u][2]+1)
{
dist[v][C]=dist[u][2]+1;
flag=1;
}
if(C!=3 && dist[v][C]>dist[u][3]+1)
{
dist[v][C]=dist[u][3]+1;
flag=1;
}
if(flag==1 && hash[v]==0)
{
hash[v]=1;
dui[++duip]=v;
}
}
}
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int p,q,r;
scanf("%d%d%d",&p,&q,&r);
Add(p,q,r,i);
}
SPFA();
int ans=MIN(MIN(dist[n][0],dist[n][1]),MIN(dist[n][2],dist[n][3]));
if(ans==0x3f3f3f3f)
cout<<-1<<endl;
else cout<<ans<<endl;
return 0;
}