题意:http://www.cnblogs.com/yylogo/archive/2011/06/05/SGU-103.html
分析:比通常的最短路问题多了个限制条件,即每个路口的颜色必须相同时才能通过,否则需要等待。不难发现,路口的颜色是与当前已经花费的时间有关。于是可以构造一个函数,根据当前所用时间来计算某个路口的颜色,以及下一次变色所需时间。
利用该函数可以计算出当前两个路口的颜色,看其是否相同。如果不同,则再看其下一次变色所需时间是否相同,若相同,则仍然无法通过,再计算下下次变色时间,若仍相同,则该两个路口的颜色将一直相反,即无法相通。这里可以画图理解。也就是说,最多需要循环3次来判断两个路口颜色是否相同。
另外此题还需注意输入时若用scanf读取字符,需加上getchar()吸收回车,不然会RE。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define N 305
struct P
{
char c;
int r,tb,tp;
}p[N];
int mp[N][N],d[N],pre[N];
bool v[N];
char color(int i,int d,int &t) //返回颜色以及下次变色的时刻
{
if(p[i].r>d)
{
t=p[i].r-d;
return p[i].c;
}
int x=d-p[i].r;
x=x%(p[i].tb+p[i].tp);
if(p[i].c=='P')
{
if(x<p[i].tb) { t=p[i].tb-x;return 'B';}
else {t=p[i].tb+p[i].tp-x;return 'P';}
}
else
{
if(x<p[i].tp){t=p[i].tp-x;return 'P';}
else {t=p[i].tb+p[i].tp-x;return 'B';}
}
}
int wait(int a,int b,int d)
{
int i,t1,t2,t=0;
for(i=1;i<=3;++i)
{
if(color(a,d,t1)==color(b,d,t2)) return t;
t+=min(t1,t2);
d+=min(t1,t2);
}
return inf;
}
int Dijkstra(int s,int e,int n)
{
int j,i;
for(i=1;i<=n;++i) d[i]=inf;
d[s]=0;
for(i=1;i<n;++i)
{
int mi=inf,u=s;
for(j=1;j<=n;++j)
if(!v[j]&&d[j]<mi)
{
u=j;
mi=d[j];
}
v[u]=1;
for(j=1;j<=n;++j)
if(!v[j]&&mp[u][j]<inf)
{
int t=wait(j,u,d[u]);
if(d[u]+mp[u][j]+t<d[j])
{
d[j]=d[u]+mp[u][j]+t;
pre[j]=u;
}
}
}
return d[e];
}
void output(int s,int e)
{
if(s==e) {printf("%d",s);return;}
output(s,pre[e]);
printf(" %d",e);
}
int main()
{
int n,m,s,e,a,b,c,ans,i;
scanf("%d%d%d%d",&s,&e,&n,&m);
getchar();
memset(mp,inf,sizeof(mp));
for(i=1;i<=n;++i) {scanf("%c%d%d%d",&p[i].c,&p[i].r,&p[i].tb,&p[i].tp);getchar();}
for(i=1;i<=m;++i) {scanf("%d%d%d",&a,&b,&c);mp[a][b]=mp[b][a]=c;}
ans=Dijkstra(s,e,n);
if(ans==inf) puts("0");
else
{
printf("%d\n",ans);
output(s,e);
puts("");
}
return 0;
}