ACM-ICPC 2018 南京赛区网络预赛 L.Magical Girl Haze

L.Magical Girl Haze

题目链接:

https://nanti.jisuanke.com/t/31001

Description

There are N cities in the country, and M directional roads from u to v(1≤u,v≤n). Every road has a distance ci. Haze is a Magical Girl that lives in City 1, she can choose no more than K roads and make their distances become 0. Now she wants to go to City N, please help her calculate the minimum distance.

Input

The first line has one integer T(1≤T≤5), then following T cases.
For each test case, the first line has three integers N,Mand K.
Then the following M lines each line has three integers, describe a road, Ui,Vi,Ci. There might be multiple
edges between u and v.
It is guaranteed that N≤100000,M≤200000,K≤10,
0≤Ci≤1e9.There is at least one path between City 1 and City N.

Output

For each test case, print the minimum distance.

Sample Input

1
5 6 1
1 2 2
1 3 4
2 4 3
3 4 1
3 5 6
4 5 2

Sample Output

3

题意

给你N个点,M条有向边,你有K次机会可以把任意一条路的权值变为0,输出1到N的最短路。

题解

dis[i][j]表示源点到i点使用了j次机会把j条路的权值变为0的最短路,这样每条路就可以扩展出两种状态:一种是接下来一条路使用一次机会dis[next][j+1],另一种是不使用dis[next][j]。然后跑SPFA。此处SPFA有一个优化:每次把点入队之前,考虑即将入队的dis值与队头的dis值的大小,若即将入队的dis值小于队头的dis值,就插入队头,否则就插入队尾(双端队列实现)。

代码

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int INF=0x3f3f3f3f;
 5 const int maxn=1e6+5;
 6 struct Edge{
 7     int e,w;
 8     Edge * pNext;
 9 };
10 struct Node{
11     int u,k;
12     Node(int uu,int kk):u(uu),k(kk){}
13     Node(){}
14 };
15 Edge G[200005],* p[maxn],*head[maxn];
16 LL dis[maxn][15];
17 int T,N,M,K,vis[maxn][15];
18 void SPFA(int v){
19     deque<Node> q;
20     int s,e,w,k;
21     for(int i=1;i<=N;++i){
22         for(int j=0;j<=K;++j){
23             dis[i][j]=INF;
24             vis[i][j]=0;
25         }
26         head[i]=p[i];
27     }
28     q.push_front(Node(v,0));
29     dis[v][0]=0;
30     vis[v][0]=1;
31     while(!q.empty()){
32         s=q.front().u;
33         k=q.front().k;
34         q.pop_front();
35         vis[s][k]=0;
36         head[s]=p[s];
37         while(head[s]){
38             e=head[s]->e;
39             w=head[s]->w;
40             if(dis[e][k]>dis[s][k]+w){
41                 dis[e][k]=dis[s][k]+w;
42                 if(!vis[e][k]){
43                     vis[e][k]=1;
44                     if(!q.empty()){
45                         if(dis[e][k]>dis[q.front().u][q.front().k]){
46                             q.push_back(Node(e,k));
47                         }else{
48                             q.push_front(Node(e,k));
49                         }
50                     }else{
51                         q.push_back(Node(e,k));
52                     }
53                 }
54             }
55             if(k+1<=K&&dis[e][k+1]>dis[s][k]){
56                 dis[e][k+1]=dis[s][k];
57                 if(!vis[e][k+1]){
58                     vis[e][k+1]=1;
59                     if(!q.empty()){
60                         if(dis[e][k+1]>dis[q.front().u][q.front().k]){
61                             q.push_back(Node(e,k+1));
62                         }else{
63                             q.push_front(Node(e,k+1));
64                         }
65                     }else{
66                         q.push_back(Node(e,k+1));
67                     }
68                 }
69             }
70             head[s]=head[s]->pNext;
71         }
72     }
73 }
74 int main(){
75     scanf("%d",&T);
76     while(T--){
77         int cnt=0,u,v,c;
78         memset(G,0,sizeof(G));
79         memset(p,0,sizeof(p));
80         scanf("%d%d%d",&N,&M,&K);
81         for(int i=0;i<M;++i){
82             scanf("%d%d%d",&u,&v,&c);
83             G[cnt].e=v;
84             G[cnt].w=c;
85             G[cnt].pNext=p[u];
86             p[u]=&G[cnt];
87             cnt++;
88         }
89         SPFA(1);
90         sort(dis[N],dis[N]+K+1);
91         printf("%lld\n",dis[N][0]);
92     }
93     return 0;
94 }

 

 

 

 

转载于:https://www.cnblogs.com/Whkkkkkkk/p/9573596.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值