zoukankan      html  css  js  c++  java
  • FZSZ Online Judge #858. 【四校联考1008】骑行川藏

    问题描述

    小C非常热衷于挑战自我,国庆假期他准备骑着自行车从福州前往成都再沿川藏线前往拉萨。川藏线的沿途有着非常美丽的风景,但在这一路上也有着很多的艰难险阻,路况变化多端,而小C的体力十分有限,因此在每天的骑行前设定好目的地、同时合理分配好自己的体力是一件非常重要的事情。

    可供小C选择的道路构成了一张连通无向图,小C的起点位于1号点,终点位于n号点,每条道路有一个困难度vi,小C定义一条路径的疲劳度为他路上经过的所有道路的困难度的最大值。一开始小C有k点体力,在通过一条道路时,他可以选择消耗若干点体力值,每消耗一点,道路的困难度也会降低1,但一条道路的困难度不能低于0。小C想知道他这次旅程的最小疲劳度。

    输入格式

    第一行三个非负整数n,m,k,分别表示图的点数,边数以及小C的初始体力值。

    接下来m行,每行三个正整数xi,yi,vi,分别表示第i条边的两个端点以及困难度。

    输出格式

    输出一个整数,表示答案。

    样例输入

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

    样例输出

    3

    数据范围

    对于20%的数据,n,m,k,vi<=1000;

    对于另外20%的数据,m=n-1;

    对于另外20%的数据,k=0;

    对于100%的数据,2<=n<=50000,m,k,vi<=50000。

    题目链接:http://192.168.68.33/problem/858.

    类似问题:luoguP1948 [USACO08JAN]电话线Telephone Lines.

    题目链接:https://www.luogu.org/problem/show?pid=1948.

    解题报告

    这题很显然是道二分题.

    首先,先二分一个答案[0,max{vi}],复杂度(logmax{vi})

    在对原图的边权进行改造:

    (1).对于vi<=mid,建边权为0的新边,

    (2).对于vi>mid,建边权为(vi-mid)的新边.

    在新图中跑一遍最短路SPFA或堆优化的Dijkstra,

    复杂度为O(km)或O(nlogm),

    个人推荐堆优化的Dijkstra,复杂度稳定.

    这样做可以找到一条最大值为mid且消耗体力最小的最优路径.

    若dis[n]<=k,则mid为可行答案,继续二分[l,mid),

    反之,mid不可行,继续二分(mid,r].

    总复杂度为O(logmax{vi}*km)或O(logmax{vi}*nlogm).

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #define pa pair<int,int>
    #define mp(x,y) make_pair(x,y)
    #define FOR(i,s,t) for(register int i=s;i<=t;++i)
    #define ll long long
    #define INF 2147483647
    #define BIG 200011
    using namespace std;
    priority_queue<pa>heap;
    int n,m,k;
    int x,y,z,tot,l,r,ans=50000;
    int nxt[BIG],to[BIG],las[BIG],w[BIG],dis[BIG],vis[BIG];
    inline void add(int x,int y,int z){
    	nxt[++tot]=las[x];
    	las[x]=tot;
    	to[tot]=y;
    	w[tot]=z;
    	return;
    }
    inline int DJ(int x){
    	FOR(i,2,n)
    		dis[i]=INF,vis[i]=0;
    	vis[1]=0;
    	heap.push(mp(0,1));
    	int now,u;
    	while(!heap.empty()){
    		now=heap.top().second;
    		heap.pop();
    		if(vis[now])
    			continue;
    		vis[now]=1;
    		for(register int e=las[now];e;e=nxt[e]){
    			u=w[e]<x?0:(w[e]-x);
    			if(dis[to[e]]>dis[now]+u){
    				dis[to[e]]=dis[now]+u;
    				heap.push(mp(-dis[to[e]],to[e]));
    			}
    		}
    	}
    	return dis[n]<=k?1:0;
    }
    inline void divide(int l,int r){
    	if(r-l<=3){
    		FOR(i,l,r)
    			if(DJ(i))
    				ans=min(ans,i);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(DJ(mid)){
    		ans=min(ans,mid);
    		divide(l,mid-1);
    	}
    	else
    		divide(mid+1,r);
    	return;
    }
    int main(){
    	scanf("%d%d%d",&n,&m,&k);
    	FOR(i,1,m){
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z);
    		add(y,x,z);
    		ans=max(z,ans);
    	}
    	r=ans;
    	divide(l,r);
    	cout<<ans<<endl;
    	return 0;
    }
    

    对于类似问题,做法类似.

    二分答案,

    改造边权:

    (1).vi<=mid,新边权为0.

    (2).vi>mid,新边权为1.

    跑一边最短路,

    复杂度为O(logmax{vi}*km)或O(logmax{vi}*nlogm).

    AC代码自己xjbYY一下能写出来了.

      

  • 相关阅读:
    ARP 协议
    天梯赛L1 题解
    DNS域名系统
    LeetCode 三角形最小路径和
    sql注入漏洞的利用
    XSS漏洞防御
    忘记密码功能漏洞挖掘
    sql bypass
    Web环境搭建组合
    常用数据库的总结
  • 原文地址:https://www.cnblogs.com/Stump/p/7679812.html
Copyright © 2011-2022 走看看