POI ZAW

 

要求一个最短路,担心的就是一条边被正反经过两次。

 

规定第一步为1到i,并把这条边设为不可经过。然后从i做最短路到1,因为这个过程是不会经历重边的(如果经历了就不是最短路了)。

求最短路用SPFA,但常数很大,会超时

但YZD大佬轻松优化到0.01s,%%%%YZD大佬orz,方法:

在SPFA时,如果dist+(i->1的路径长)大于ans就没有必要拓展,就不入队

提供YZD大佬博客链接:http://www.cnblogs.com/Lumberjack/

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 struct Node
 7 {
 8     int next,to,dis;
 9 }edge[200001];
10 int head[50001],num,q[2000001],n,m;
11 int dist[50001],map[50001],ans=2e9;
12 bool vis[50001];
13 void add(int u,int v,int d)
14 {
15     num++;
16     edge[num].next=head[u];
17     head[u]=num;
18     edge[num].to=v;
19     edge[num].dis=d;
20 }
21 void SPFA(int x)
22 {int h,t,i;
23     memset(dist,-1,sizeof(dist));
24     memset(vis,0,sizeof(vis));
25     q[1]=1;
26     h=0;t=1;
27     dist[1]=0;
28     while (h<t)
29     {
30         h++;
31         int u=q[h];
32         vis[u]=0;
33         for (i=head[u];i;i=edge[i].next)
34         {
35           int v=edge[i].to;
36           if ((u==1&&v==x)||(u==x&&v==1)) continue;
37         if (dist[u]+edge[i].dis+map[x]<=ans)
38            if (dist[v]>dist[u]+edge[i].dis||dist[v]==-1)
39            {
40               dist[v]=dist[u]+edge[i].dis;
41               if (vis[v]==0)
42               {
43                  t++;
44                  q[t]=v;
45                  vis[v]=1;
46               }
47            }
48         }
49     }
50 }
51 int main()
52 {int i,j,u,v,d,c;
53  //freopen("zaw.in","r",stdin);
54  //freopen("zaw.out","w",stdout);
55     cin>>n>>m;
56     memset(map,127/3,sizeof(map));
57     for (i=1;i<=m;i++)
58     {
59         scanf("%d%d%d%d",&u,&v,&c,&d);
60         add(u,v,c);
61         add(v,u,d);
62         if (v==1) map[u]=c;
63         if (u==1) map[v]=d;
64     }
65      for (i=2;i<=n;i++)
66      {
67         SPFA(i);
68         if (dist[i]==-1||map[i]==-1) continue;
69         ans=min(ans,map[i]+dist[i]);
70      }
71      cout<<ans<<endl;
72 }

 

转载于:https://www.cnblogs.com/Y-E-T-I/p/7423507.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值