POJ3662 SPFA//二分 + 双端队列最短路
https://cn.vjudge.net/problem/12427/origin
题意:求1到N第K + 1大条边权最小的路径
首先想到dp递推,dp[x][y]表示到x这个点经过y条免费边的最小值。
直接借助SPFA递推即可
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = ;
const int maxm = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,tmp,K;
struct Edge{
int v,w,next;
}edge[maxm * ];
int head[maxn],tot;
void init(){
Mem(head,-);
tot = ;
}
void add(int u,int v,int w){
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
bool vis[maxn][maxn];
int dp[maxn][maxn]; // 到达i经过p条免费边最大值
struct Node{
int p,x,cost;
Node(int x = ,int p = ,int cost = ):x(x),p(p),cost(cost) {}
};
void SPFA(){
queue<Node>Q;
Q.push(Node(,,));
while(!Q.empty()){
Node u = Q.front(); Q.pop();
vis[u.x][u.p] = ;
for(int i = head[u.x];~i;i = edge[i].next){
int v = edge[i].v;
if(dp[v][u.p] > max(dp[u.x][u.p],edge[i].w)){
dp[v][u.p] = max(dp[u.x][u.p],edge[i].w);
if(!vis[v][u.p]){
vis[v][u.p] = ;
Q.push(Node(v,u.p,dp[v][u.p]));
}
}
if(u.p < K && dp[v][u.p + ] > dp[u.x][u.p]){
dp[v][u.p + ] = dp[u.x][u.p];
if(!vis[v][u.p + ]){
vis[v][u.p + ] = ;
Q.push(Node(v,u.p + ,dp[v][u.p + ]));
}
}
}
}
}
int main()
{
scanf("%d%d%d",&N,&M,&K);
init();
For(i,,M){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w);
}
memset(dp,0x3f,sizeof(dp));
dp[][] = ;
SPFA();
int ans = INF;
_For(i,K,){
ans = min(ans,dp[N][i]);
}
if(ans == INF) Pri(-);
else Pri(ans);
#ifdef VSCode
system("pause");
#endif
return ;
}
SPFA
第二个思想是二分答案,将大于这个答案的边权变为0,小于这个答案的边权变为1,直接跑1到N的最短路进行check
对于01图的最短路有一个技巧是用双端队列,类似BFS的方法跑,将权值为1的边进入的点加到队尾,权值0到达的点加到队尾即可。
#include <map>
#include <set>
#include <deque>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = ;
const int maxm = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,tmp,K;
struct Edge{
int v,w,next;
}edge[maxm * ];
int head[maxn],tot;
void init(){
Mem(head,-);
tot = ;
}
void add(int u,int v,int w){
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
bool vis[maxn];
int dis[maxn];
bool check(int x){
deque<int>Q;
Q.push_back();
Mem(vis,);
Mem(dis,0x3f);
dis[] = ;vis[] = ;
while(!Q.empty()){
int u = Q.front(); Q.pop_front();
if(u == N) return dis[u] <= K;
for(int i = head[u]; ~i; i = edge[i].next){
int v = edge[i].v; int w = edge[i].w;
if(w <= x){
dis[v] = min(dis[v],dis[u]);
if(!vis[v]) Q.push_front(v);
}
else{
dis[v] = min(dis[v], + dis[u]);
if(!vis[v]) Q.push_back(v);
}
vis[v] = ;
}
}
return false;
}
int solve(int r){
int l = ;
int ans = -;
while(l <= r){
int m = (l + r) >> ;
if(check(m)){
ans = m;
r = m - ;
}else{
l = m + ;
}
}
return ans;
}
int main()
{
int MAX = ;
scanf("%d%d%d",&N,&M,&K);
init();
For(i,,M){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
MAX = max(MAX,w);
add(u,v,w); add(v,u,w);
}
Pri(solve(MAX));
#ifdef VSCode
system("pause");
#endif
return ;
}
POJ3662 SPFA//二分 + 双端队列最短路的更多相关文章
- 电路维修(双端队列 & 最短路)
达达是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女翰翰,从而被收留在地球上. 翰翰的家里有一辆飞行车. 有一天飞行车的电路板突然出现了故障,导致无法启动. 电路板的整体结构是一个$ ...
- 关于SPFA的双端队列优化
7.11 Update 我做题的时候发现这样写会RE 因为在使用双端队列优化SPFA的时候 在将一个点加入队列的时候,如果队列已经空了 那么一旦出现dis[Q.front()]就会RE 可以这样修改 ...
- POJ-3662 Telephone Lines 二分+双端队列
题目传送门 题意:有n个点, p条路,每条道路有个花费Li, 然后现在要建一条1-n的路线,然后可以选k条道路免费, 然后可以在剩下的道路中选择价格最高的边支付费用, 求这个答案最小. 题解: 二分答 ...
- POJ 3662 Telephone Lines【二分答案+最短路】||【双端队列BFS】
<题目链接> 题目大意: 在一个节点标号为1~n的无向图中,求出一条1~n的路径,使得路径上的第K+1条边的边权最小. 解题分析:直接考虑情况比较多,所以我们采用二分答案,先二分枚举第K+ ...
- poj 3259 Wormholes : spfa 双端队列优化 判负环 O(k*E)
/** problem: http://poj.org/problem?id=3259 spfa判负环: 当有个点被松弛了n次,则这个点必定为负环中的一个点(n为点的个数) spfa双端队列优化: 维 ...
- 2601 电路维修 (双端队列bfs\优先队列bfs(最短路))
描述 Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上.Rika的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障,导致无法启动. 电路板 ...
- P - The Shortest Path in Nya Graph-hdu4725(双端队列+拆点)
题意:有N个点和N层..一层有X个点(0<=X<=N).两邻两层间有一条路花费C.还有M条小路在两个点之间.问从第一个点走到第N个点最短路是多少... 可以考虑在每一层增加一个点,这个点到 ...
- 洛谷P3222 [HNOI2012]射箭(计算几何,半平面交,双端队列)
洛谷题目传送门 设抛物线方程为\(y=ax^2+bx(a<0,b>0)\),我们想要求出一组\(a,b\)使得它尽可能满足更多的要求.这个显然可以二分答案. 如何check当前的\(mid ...
- CH 2601 - 电路维修 - [双端队列BFS]
题目链接:传送门 描述 Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上.Rika的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障,导致 ...
随机推荐
- codeforces534B
Covered Path CodeForces - 534B The on-board computer on Polycarp's car measured that the car speed a ...
- Keepalived+LVS高可用负载均衡集群
概述 Keepalived是专门针对LVS设计的一款强大的辅助工具,主要用来提供故障切换(Failover)和健康检查(HeathChecking)功能——判断LVS负载调度器.节点服务器的可用性,及 ...
- luogu P1077 摆花
这道题看似好难,但是其实很简单 先把题目中所让你设的变量都设好,该输入的都输入 你会发现这道题好像成功了一半,为什么呢??? 因为设完后你会发现你不需要再添加任何变量,已经足够了. 可能最难的地方,就 ...
- Android 下载App
转载:http://blog.csdn.net/aicpzl/article/details/52993074 通过DownloadManager来下载APK到本地,下载完成后收到广播再安装APK,可 ...
- P1064 金明的预算方案
思路:就是一个背包问题 因为数据范围小,所以不把 1个带附着物的东西 拆成 带1个带2个或不带 #include<bits/stdc++.h> using namespace std; ...
- UOJ272 [清华集训2016] 石家庄的工人阶级队伍比较坚强 【分治乘法】
题目分析: 首先不难注意到式子就是异或卷积,所以考虑用分治乘法推出优化方法.我们把一个整体$f$拆成$f-,f\pm,f+$,然后另一个拆成$g-,g\pm,g+$.这样做的好处是能更清楚的分析问题. ...
- Quartus prime 16.0 signaltap II 使用
前言 由于逻辑分析仪太贵,altera贴心提供signal tap II来观察输出波形,不过使能signaltap II会占用片内ram,毕竟原理就是把数据采样到ram中再通过jtag口上传到quar ...
- 【XSY1538】连在一起的幻想乡 数学 无向连通图计数
题目大意 给你\(n,p\),求\(n\)个点组成的所有无向连通图的边数的平方和模\(p\) \(n\leq 2000,p\leq {10}^9\) 题解 设\(m=\frac{n(n-1 ...
- 理解Spark的核心RDD
http://www.infoq.com/cn/articles/spark-core-rdd/
- python 获取当前文件夹下所有文件名
os 模块下有两个函数: os.walk() os.listdir() 1 # -*- coding: utf-8 -*- 2 3 import os 4 5 def file_name(file_d ...