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的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障,导致 ...
随机推荐
- rediret 加/与不加/的区别
- 进程间通信IPC与Binder机制原理
1, Intent隐式意图携带数据 2, AIDL(Binder) 3, 广播BroadCast 4, 内容提供者ContentProvider 5,Messager(内部通过binder实现) 6, ...
- ES系列十五、ES常用Java Client API
一.简介 1.先看ES的架构图 二.ES支持的客户端连接方式 1.REST API http请求,例如,浏览器请求get方法:利用Postman等工具发起REST请求:java 发起httpClien ...
- memcached安装报错 error while loading shared libraries: libevent-2.0.so.5: cannot open shared object file: No such file or directory解决
我是从其他服务器scp来的memcached(~~~整个文件夹的那种,windows用多了的后遗症) 在准备运行 ./memcached -d -u root -l localhost -m 800 ...
- 洛谷P1226 【模板】快速幂||取余运算
题目描述 输入b,p,k的值,求b^p mod k的值.其中b,p,k*k为长整型数. 输入输出格式 输入格式: 三个整数b,p,k. 输出格式: 输出“b^p mod k=s” s为运算结果 S1: ...
- SPOJ QTREE-Query on a tree-树链剖分-边权
用每个点代表父节点到此点的边.建立一一映射后就可以用点权的方法处理了. 注意的是路径两端节点的处理 #include <cstdio> #include <algorithm> ...
- BZOJ4653 [NOI2016] 区间 【线段树】
题目分析: 首先思考一个二分答案的做法.我们可以注意到答案具有单调性,所以可以二分答案. 假设当前二分的答案是$ k $.那么按照大小顺序插入每个区间,同时在末端删除会对答案产生影响的区间.这里不妨用 ...
- SpringBoot添加CORS跨域
配置CORSConfiguration 添加CORS的配置信息,我们创建一个CORSConfiguration配置类重写如下方法,如图所示: @Override public void addCors ...
- jemter的使用
1.启动jmeter
- 启发式合并&线段树合并/分裂&treap合并&splay合并
启发式合并 有\(n\)个集合,每次让你合并两个集合,或询问一个集合中是否存在某个元素. 我们可以用平衡树/set维护集合. 对于合并两个\(A,B\),如果\(|A|<|B|\),那么 ...