ACM-ICPC 2018 南京赛区网络预赛 L. Magical Girl Haze 最短路变形 dp

62 篇文章 0 订阅

There are N cities in the country, and M directional roads from uto 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,M and K.

Then the following MMM 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.

样例输入

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

样例输出

3

题意:

       给你n个城市,m条路,每条路都要花费一定的时间,现在有个人想从城市1走到城市n,但是他可以选最多k条路把它的时间变成0,问他走到城市n的最少时间。

 

做法:

      很明显因为存在k条可变的边,普通的最短路肯定做不了,需要用到一定的dp,dp[i][j]代表走到点i,用掉j次机会所用的最少时间。要配合dijkstra一起更新,同时设定一个vis来剪枝,就可以过了。


#include<cstring>
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int mod=(int)1e9+7;
const int maxn=100005;
const ll inf=1e17;
int n,m,head[maxn],now,k;
bool vis[maxn][11];
ll dp[maxn][11];
struct node{
    int to,next;
    ll w;
}e[2*maxn];
void add(int u,int v,ll w){
    e[now].to=v; e[now].w=w;
    e[now].next=head[u],head[u]=now++;
}
struct  Node{
    ll dis;
    int id,num;
    Node(int num,int dis,int id):num(num),dis(dis),id(id){}
    bool operator < (const Node &a)const{
        if(dis!=a.dis) return dis>a.dis;
        return num>a.num;
    }
};
void dij(int st){
    priority_queue<Node> q;
    q.push(Node(0,0,st));
    dp[st][0]=0;
    while(!q.empty()){
        Node u=q.top(); q.pop();
        if(vis[u.id][u.num]) continue;
        vis[u.id][u.num]=1;
        for(int i=head[u.id];~i;i=e[i].next){
            int v=e[i].to;
            if(dp[v][u.num]-e[i].w>dp[u.id][u.num]){
                dp[v][u.num]=dp[u.id][u.num]+e[i].w;
                q.push(Node(u.num,dp[v][u.num],v));
            }
            if(u.num<k&&dp[v][u.num+1]>dp[u.id][u.num]){
                dp[v][u.num+1]=dp[u.id][u.num];
                q.push(Node(u.num+1,dp[v][u.num+1],v));
            }
        }
    }
}
void init(){
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
    memset(dp,125,sizeof(dp));
    now=0;
}
int main(){
    int t,x,y;
    ll z;
    cin>>t;
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        init();
        for(int i=0;i<m;i++){
            scanf("%d%d%lld",&x,&y,&z);
            add(x,y,z);
        }
        dij(1);
        printf("%lld\n",dp[n][k]);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值