P3759道路升级

时间限制 : - MS 空间限制 : 65536 KB
评测说明 : 时限1000ms
问题描述

每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M.
道路i连接牛棚P1_i和P2_i (1 <= P1_i <= N; 1 <= P2_i<= N). John需要T_i (1 <=
T_i <= 1,000,000)时间单位用道路i从P1_i走到P2_i或者从P2_i 走到P1_i
他想更新一些路经来减少每天花在路上的时间.具体地说,他想更新K (1 <= K <=
20)条路经,将它们所须时间减为0.帮助FJ选择哪些路经需要更新使得从1到N的时间尽量少.

输入格式

  • 第一行: 三个空格分开的数: N, M, 和 K
  • 第2..M+1行: 第i+1行有三个空格分开的数:P1_i, P2_i, 和 T_i

输出格式

第一行: 更新最多K条路经后的最短路经长度

样例输入

4 4 1
1 2 10
2 4 10
1 3 1
3 4 100

样例输出

1

提示

样例说明:
K是1; 更新道路3->4使得从3到4的时间由100减少到0. 最新最短路经是1->3->4,总用时为1单位. N<=10000

题解

多维最短路 考虑dis[n][k]表示到n点免费k条边的最小值。
所以:1.dis[en][k]=min(dis[en][k],dis[x][k]+len[i]);
2.dis[en][k+1]=min(dis[x][k],dis[en][k+1]);

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<map>
using namespace std;
#define maxn2 110000
int n,m,k;
struct node{
    int a,b,d;
};
priority_queue<node>q;
bool operator <(node a,node b)
{
    return a.d>b.d;
} 
int cnt;
int Last[maxn2],Next[maxn2],End[maxn2],Len[maxn2];
int dis[maxn2][21];
bool mark[maxn2][21];
void insert(int x,int y,int z)
{
    Next[++cnt]=Last[x];
    Last[x]=cnt;
    End[cnt]=y;
    Len[cnt]=z;
}
void d(int x)
{
    int i,m;
    node tmp;
    memset(dis,60,sizeof(dis));
    dis[x][0]=0;
    tmp.a=x;tmp.b=0;tmp.d=dis[x][0];
    q.push(tmp);
    while(q.size())
    {
        int s,kk;
        node temp=q.top();
        q.pop();
        s=temp.a;
        kk=temp.b;
        if(mark[s][kk]==true) continue;
        mark[s][kk]=true;
        for(i=Last[s];i;i=Next[i])
        {
            int en=End[i];
            if(dis[en][kk]>dis[s][kk]+Len[i])
            {
                dis[en][kk]=dis[s][kk]+Len[i];
                tmp.a=en;tmp.b=kk;tmp.d=dis[en][kk];
                q.push(tmp);
            }
            if(kk+1<=k&&dis[s][kk]<dis[en][kk+1])
            {
                dis[en][kk+1]=dis[s][kk];
                tmp.a=en;tmp.b=kk+1;tmp.d=dis[en][kk+1];
                q.push(tmp);
            }
        }
    }
}
int main()
{
    int i;
    scanf("%d%d%d",&n,&m,&k);

    for(i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        insert(x,y,z);
        insert(y,x,z);
    }
    d(1);
    cout<<dis[n][k];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值