qzezoj 1543 最快路线
题面传送门
看到这道题,想到\(spfa\)。
但这道题好像故意的,偏偏又路牌被拆的道路(在衢州的话负责那一段路的交警就该下台了),
所以我们不能只以\(d_i\)为\(time\)的唯一标准。
想象一下:如果下一条路是没有路牌的,而这时过来一条路,\(time\)比\(d_i\)大,但如果下一条路可以走得通怎么办?而且还走得比\(d_i\)快。这时候就进退两难,如果放过去,那\(spfa\)就废了。
如果不放过去,答案就废了。
想想\(flying\)经常说什么?\(dp\)状态表达不完整就再加一维状态!我们可以用\(dp\)的思路:以\(d_{i,j}\)表示以\(j\)速度开到\(i\)点所需最短时间。那么\(spfa\)还是照样松弛呗。
这道题要求我们输出经过点序,所以我们可以\(spfa\)的过程中当出现一个最优解时指回去。然后最后倒序输出。
代码实现:
#include<cstdio>
#include<queue>
using namespace std;
int n,m,k,x,y,z,h,zj[100039],head,now1[159][559],now2[159][559],tmp1,tmp2;
double dp[159][559],ans;
struct yyy{
int a,b,c;
}f[159][159],cur;
struct fs{
int mu,su;
}tmp;
queue<fs> q;
int main(){
// freopen("1.in","r",stdin);
int i,j;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=m;i++) scanf("%d%d%d%d",&x,&y,&z,&h),f[x][++f[x][0].a]=(yyy){y,z,h};
q.push((fs){0,70});
for(i=0;i<=500;i++) now1[0][i]=-1,now2[0][i]=-1;
for(i=0;i<=150;i++){
for(j=0;j<=550;j++) dp[i][j]=100000000;
}
dp[0][70]=0;
while(!q.empty()){
tmp=q.front();
q.pop();
for(i=1;i<=f[tmp.mu][0].a;i++){
cur=f[tmp.mu][i];
if(!cur.b){
ans=dp[tmp.mu][tmp.su]+cur.c*1.0/tmp.su;
if(ans<dp[cur.a][tmp.su]){
dp[cur.a][tmp.su]=ans;
now1[cur.a][tmp.su]=tmp.mu;
now2[cur.a][tmp.su]=tmp.su;
q.push((fs){cur.a,tmp.su});
}
}
else{
ans=dp[tmp.mu][tmp.su]+cur.c*1.0/cur.b;
if(ans<dp[cur.a][cur.b]){
dp[cur.a][cur.b]=ans;
now1[cur.a][cur.b]=tmp.mu;
now2[cur.a][cur.b]=tmp.su;
q.push((fs){cur.a,cur.b});
}
}
}
}
//printf("%d %d %d %d %d %d %d %d\n",now1[1][64],now2[1][64],now1[3][90],now2[3][90],now1[2][90],now2[2][90],now1[5][70],now2[5][70]);
ans=1000000000;
for(i=1;i<=550;i++){
if(dp[k][i]>0) ans=min(ans,dp[k][i]);
}
for(i=1;i<=550;i++){
if(dp[k][i]==ans){
tmp1=now1[k][i];tmp2=now2[k][i];
printf("0");
while(tmp1){
zj[++head]=tmp1;
h=tmp1;x=tmp2;
tmp1=now1[h][x];tmp2=now2[h][x];
}
for(j=head;j>=1;j--) printf(" %d",zj[j]);
printf(" %d",k);
}
}
}
然而又要卡常......可能这道题有卡\(spfa\)的数据吧......
加寄存器,手写队列......又是卡过去的......\(966ms\)。本机都跑的飞快呀......
代码实现:
#include<cstdio>
#include<queue>
using namespace std;
int zj[1039],now1[159][559],now2[159][559];
double dp[159][559],ans;
struct yyy{
int a,b,c;
}f[159][159];
struct fs{
int mu,su;
}q[500039];
inline void read(int &x){
x=0;char s=getchar();
while(s<'0'||s>'9') s=getchar();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
int main(){
// freopen("fast.in","r",stdin);
// freopen("fast.out","w",stdout);
register int i,j,he=0,ta=0,cura,curb,tmpsu,tmpmu,curc,n,m,k,x,y,z,h,head=0,tmp1,tmp2;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=m;i++) read(x),read(y),read(z),read(h),f[x][++f[x][0].a]=(yyy){y,z,h};
q[++ta]=((fs){0,70});
for(i=0;i<=500;i++) now1[0][i]=-1,now2[0][i]=-1;
for(i=0;i<=n;i++){
for(j=0;j<=500;j++) dp[i][j]=1000000000;
}
dp[0][70]=0;
while(he!=ta){
tmpsu=q[he+1].su;tmpmu=q[he+1].mu;
he++;
for(i=f[tmpmu][0].a;i>=1;i--){
cura=f[tmpmu][i].a;curb=f[tmpmu][i].b;curc=f[tmpmu][i].c;
if(!curb){
ans=dp[tmpmu][tmpsu]+curc*1.0/tmpsu;
if(ans<dp[cura][tmpsu]){
dp[cura][tmpsu]=ans;
now1[cura][tmpsu]=tmpmu;
now2[cura][tmpsu]=tmpsu;
q[++ta]=((fs){cura,tmpsu});
}
}
else{
ans=dp[tmpmu][tmpsu]+curc*1.0/curb;
if(ans<dp[cura][curb]){
dp[cura][curb]=ans;
now1[cura][curb]=tmpmu;
now2[cura][curb]=tmpsu;
q[++ta]=((fs){cura,curb});
}
}
}
}
//printf("%d %d %d %d %d %d %d %d\n",now1[1][64],now2[1][64],now1[3][90],now2[3][90],now1[2][90],now2[2][90],now1[5][70],now2[5][70]);
ans=1000000000;
for(i=1;i<=500;i++){
if(dp[k][i]>0) ans=min(ans,dp[k][i]);
}
for(i=1;i<=500;i++){
if(dp[k][i]==ans){
tmp1=now1[k][i];tmp2=now2[k][i];
while(tmp2!=-1&&tmp1!=-1){
zj[++head]=tmp1;
h=tmp1;
tmp1=now1[h][tmp2];tmp2=now2[h][tmp2];
}
for(j=head;j>=1;j--) printf("%d ",zj[j]);
printf("%d ",k);
}
}
}