AOJ2249 最短路+最小花费(双权值)

写题解之前先骂一下这道题

xxx给数据范围点数<1e4,边数<2e4,结果我开2e4和3e4都RE,然后找问题一个多小时,最后我开了1e5和2e5,题面太能唬人了吧!?真是sb题面

------------------------------------------分割线------------------------------------

题目大意:给n个点和m条边,每条边给了起始点,距离和价格,求在保证点1到其他n-1个点的路径都是最短路的前提下所有路的价格之和的最小值

简单的Dijkstra变形,在松弛的时候做一下改变即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 #include<cstring>
 5 #define mem(a,b) memset(a,b,sizeof(a))
 6 using namespace std;
 7 struct edge
 8 {
 9     int to,nex,v,p;
10 }e[220000];
11 int cnt,dis[110000],pri[110000];
12 int vis[110000],fir[110000];
13 struct node
14 {
15     int dis,pos;
16     node(){};
17     node(int a,int b):dis(a),pos(b){}
18     bool operator<(const node &x)const
19     {
20         return dis>x.dis;
21     }
22 };
23 void add_e(int fro,int to,int v,int p)
24 {
25     e[++cnt].v=v;
26     e[cnt].to=to;
27     e[cnt].nex=fir[fro];
28     e[cnt].p=p;
29     fir[fro]=cnt;
30 }
31 void dij(int s)
32 {
33     priority_queue<node>q;
34     q.push(node(0,1));
35     while(!q.empty())
36     {
37         int now=q.top().pos;
38         q.pop();
39         if(vis[now]) continue;
40         vis[now]=1;
41         for(int i=fir[now];i;i=e[i].nex)
42         {
43             int to=e[i].to;
44             if(dis[to]>dis[now]+e[i].v&&vis[to]==0)
45             {
46                 dis[to]=dis[now]+e[i].v;
47                 pri[to]=e[i].p;     /*松弛以后更改花费,因为是由上一个点扩展来的,为了避免重复计数,
48                                     花费直接就是边的价格,
49                                     不理解的话可以这样想,所有的点都是由上一个点找到的,
50                                     然后最终会到第一个点,所以总的花费=这个点的花费+之前点的花费,一直推直到点1*/
51                 q.push(node(dis[to],to));
52             }
53             else if(dis[to]==dis[now]+e[i].v)//注意此处一定要用else if,因为上一个if进行之后,这个if必定满足(或者把这个if写在前面)
54             {
55                 pri[to]=min(e[i].p,pri[to]);//距离相同选择最小花费
56             }
57         }
58     }
59 }
60 void ini()
61 {
62     cnt=0;
63     fill(dis,dis+110000,99999999);
64     fill(pri,pri+110000,99999999);
65     mem(fir,0);
66     mem(e,0);
67     mem(vis,0);
68 }
69 int main()
70 {
71     int m,n;
72     while(scanf("%d%d",&n,&m)&&m+n)
73     {
74         ini();
75         dis[1]=0;
76         for(int i=1;i<=m;i++)
77         {
78             int a,b,c,d;
79             cin>>a>>b>>c>>d;
80             add_e(a,b,c,d);
81             add_e(b,a,c,d);
82         }
83         dij(1);
84         int ans=0;
85         for(int i=2;i<=n;i++)
86         {
87             ans+=pri[i];//加起来就是总的花费
88         }
89         printf("%d\n",ans);
90     }
91     return 0;
92 }
View Code

 

转载于:https://www.cnblogs.com/codeoosacm/p/10066953.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值