poj_3662 最小化第k大的值
题目大意
有N个节点以及连接的P个无向边,现在要通过这P条边从1号节点连接到N号节点。若无法连接成功,则返回-1;若能够连接成功,那么其中用到了L条边,这L条边中有K条边可以免费,L-K条边不能免费,求出不能免费的边的最大长度。
题目分析
判断能否到达,可以通过BFS搜索路径,若不能到达,返回-1;若能到达,且最少需要的路径的边数小于等于K,那么所有的边都可以免费,则返回0;若能够到达,且最少需要的路径边数大于K,则需要求出从节点1到节点N的路径中第K+1长的边的最小值,即最小化第k大的值问题。
用二分法,枚举边长x,若路径中大于等于x的边数大于K,则说明x在构成路径的边长序列中的序号大于K+1,则将x增大;若路径中大于等于x的边长小于等于K,则说明x在构成路径的边长序列中的序号小于等于K+1,因此将x减小.... 直到x为最小的满足路径中边长大于等于x的边数大于K的最小值,则x即为路径中第K+1大的边,且X最小。
那么,对于一个长度x,该选择哪条路径呢?由于要求的最小的x,那么就要求路径中边长大于等于x的个数尽可能的少(若个数少于等于K,则减小x),转换一下,将路径中长度大于等于x的边权值设为1,小于x的权值设为0,则走一条从源到汇的路径,路径中边的权值和最小即对应路径中边长大于等于x的个数最少。
求最短路径,使用Dijkstra算法即可。
实现(c++)
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define MAX_NODE 1005
#define MAX_EDGE 20005
#define INF 1 << 28
#define min(a, b) a < b?a:b
#define max(a, b) a >b? a:b
struct Edge{
int to;
int d;
int next;
};
struct NodeDist{
int v;
int d;
NodeDist(int vv = 0, int dd = 0) :
v(vv), d(dd){};
};
struct Cmp{
bool operator()(const NodeDist& e1, const NodeDist& e2){
return e1.d > e2.d;
}
};
Edge gEdges[MAX_EDGE];
int gEdgeCount;
int gHead[MAX_NODE];
int gDist[MAX_NODE];
bool gVisited[MAX_NODE];
void InsertEdge(int u, int v, int d){
int e = gEdgeCount++;
gEdges[e].to = v;
gEdges[e].d = d;
gEdges[e].next = gHead[u];
gHead[u] = e; e = gEdgeCount++;
gEdges[e].to = u;
gEdges[e].d = d;
gEdges[e].next = gHead[v];
gHead[v] = e;
} int Dijkstra(int s, int t, int k){
memset(gVisited, false, sizeof(gVisited));
memset(gDist, 0x7F, sizeof(gDist));
gDist[s] = 0;
priority_queue<NodeDist, vector<NodeDist>, Cmp> pq;
pq.push(NodeDist(s, 0));
NodeDist nd;
while (!pq.empty()){
nd = pq.top();
pq.pop();
if (gVisited[nd.v])
continue;
gVisited[nd.v] = true;
if (nd.v == t){
break;
}
for (int e = gHead[nd.v]; e != -1; e = gEdges[e].next){
int v = gEdges[e].to;
if (gDist[v] > gDist[nd.v] + (gEdges[e].d >= k)){
gDist[v] = gDist[nd.v] + (gEdges[e].d >= k);
pq.push(NodeDist(v, gDist[v]));
}
}
}
return gDist[t];
} int MinStep(int s, int t){
bool visited[MAX_NODE];
memset(visited, false, sizeof(visited));
queue<pair<int, int> > Q;
Q.push(pair<int, int>(s, 0));
visited[s] = true;
while (!Q.empty()){
pair<int, int> p = Q.front();
Q.pop();
if (p.first == t){
return p.second;
}
for (int e = gHead[p.first]; e != -1; e = gEdges[e].next){
if (!visited[gEdges[e].to]){
Q.push(pair<int, int>(gEdges[e].to, p.second + 1));
visited[gEdges[e].to] = true;
}
}
}
return -1;
} int gEdgeDist[MAX_EDGE];
int main(){
int n, p, k, u, v, d, e_count;
while (scanf("%d %d %d", &n, &p, &k) != EOF){
memset(gHead, -1, sizeof(gHead));
gEdgeCount = 0;
e_count = 0;
for (int i = 0; i < p; i++){
scanf("%d %d %d", &u, &v, &d);
InsertEdge(u, v, d);
gEdgeDist[e_count++] = d;
} int min_step = MinStep(1, n);
if (min_step == -1){
printf("-1\n");
continue;
}
else if (min_step <= k){
printf("0\n");
continue;
} sort(gEdgeDist, gEdgeDist + e_count);
int beg = 0, end = e_count, mid;
int rr;
while (beg < end){
mid = (beg + end) / 2;
int t = Dijkstra(1, n, gEdgeDist[mid]);
if (t <= k){
end = mid;
}
else{
rr = gEdgeDist[mid];
beg = mid + 1;
}
}
//最后得到的是,满足路径中边长大于等于 x 的长度的边数 大于k 最大的 x printf("%d\n", rr);
}
return 0;
}
poj_3662 最小化第k大的值的更多相关文章
- POJ 3662 Telephone Lines (二分+Dijkstra: 最小化第k大的值)
题意 Farmer John想从电话公司修一些电缆连接到他农场.已知N个电线杆编号为1,2,⋯N,其中1号已经连接电话公司,N号为农场,有P对电线杆可连接. 现给出P对电线杆距离Ai,Bi,Li表示A ...
- POJ-3662 Telephone Lines---二分+最短路+最小化第k+1大
题目链接: https://cn.vjudge.net/problem/POJ-3662 题目大意: 求一条路径从1到n使第k+1大的边最小. 解题思路: 二分答案mid,当原边权小于等于mid新边权 ...
- 利用划分树求解整数区间内第K大的值
如何快速求出(在log2n的时间复杂度内)整数区间[x,y]中第k大的值(x<=k<=y)? 其实我刚开始想的是用快排来查找,但是其实这样是不行的,因为会破坏原序列,就算另外一个数组来存储 ...
- 查找第K大的值
这种题一般是给定N个数,然后N个数之间通过某种计算得到了新的数列,求这新的数列的第K大的值 POJ3579 题意: 用$N$个数的序列$x[i]$,生成一个新序列$b$. 新的序列定义为:对于任意的$ ...
- 算法---数组总结篇2——找丢失的数,找最大最小,前k大,第k小的数
一.如何找出数组中丢失的数 题目描述:给定一个由n-1个整数组成的未排序的数组序列,其原始都是1到n中的不同的整数,请写出一个寻找数组序列中缺失整数的线性时间算法 方法1:累加求和 时间复杂度是O(N ...
- 两个已排序数组进行合并后的第K大的值--进军硅谷
我看到此题时,首先想到一个一个比较遍历过去,这是最暴力的方法,后面我想到了已经排序,那么对每个数组进行二分,然后比较这两个值.此书第三种解法,挺不错,只对那个长度较小的数组进行二分查找,保证i+j-1 ...
- POJ_3579_Median_(二分,查找第k大的值)
描述 http://poj.org/problem?id=3579 给你一串数,共C(n,2)个差值(绝对值),求差值从大到小排序的中值,偶数向下取. Median Time Limit: 1000M ...
- POJ 3579 3685(二分-查找第k大的值)
POJ 3579 题意 双重二分搜索:对列数X计算∣Xi – Xj∣组成新数列的中位数 思路 对X排序后,与X_i的差大于mid(也就是某个数大于X_i + mid)的那些数的个数如果小于N / 2的 ...
- 215. Kth Largest Element in an Array找出数组中第k大的值
堆排序做的,没有全部排序,找到第k个就结束 public int findKthLargest(int[] nums, int k) { int num = 0; if (nums.length &l ...
随机推荐
- 【C#/WPF】如何查看System.Windows.Interactivity.dll中EventTrigger的EventNames属性有哪些
WPF项目中,从Nuget搜索并下载System.Windows.Interactivity.dll,安装到项目中,并在XAML界面引入. <UserControl xmlns:i=" ...
- java资料——哈希表(散列表)(转)
哈希表 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度. ...
- OpenResty(Nginx+Lua)开发入门
Nginx入门 本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章: nginx启动.关闭.重启 http://www.cnblogs.com/derekchen/archi ...
- A/libc:fatal signal 11(SIGSEGV).code 1, fault addr 0x0 in tid 26488 (VideoEncoder)
在调试Camera模块:发现相同的代码在厂家提供的环境里边编译.就是ok的,在我们的源码树中编译,将HAL库推进去后.就会signal 11退出. 一.现象 F/libc ( ): Fatal sig ...
- Qt 线程基础(QThread、QtConcurrent等)
[-] 使用线程 何时使用其他技术替代线程 应该使用 Qt 线程的哪种技术 Qt线程基础 QObject与线程 使用互斥量保护数据的完整 使用事件循环防止数据破坏 处理异步执行 昨晚看Qt的Manua ...
- TCP/IP和Socket的关系
要写网络程序就必须用Socket,这是程序员都知道的.而且,面试的时候,我们也会问对方会不会Socket编程?一般来说,很多人都会说,Socket编程基本就是listen,accept以及send,w ...
- (转)深入解析SendMessage、PostMessage
转自:http://blog.csdn.net/xt_xiaotian/article/details/2778689 本文将使用C++语言,在MFC框架的配合下给出PostMessage.S ...
- (转)Invalidate、RedrawWindow与UpdateWindow的区别
一:什么时候才会发生重绘窗口的消息? 当需要更新或重新绘制窗口的外观时,应用程序就会发送WM_PAINT消息.对窗口进行重新绘制. 二:Invalidate() -- RedrawWindow() ...
- MySQl安装全解
这是第二次安装MySql了.第一次安装花了几个小时,理解安装的每一个页面,这次光寻找安装包就找了几个.因此感觉有必要做一次全面的安装笔记.(有点浪费时间了,可是感觉非常值得)本人系统是window7. ...
- hdu 4463 Outlets
#include<bits/stdc++.h> using namespace std; double x[100+5],y[100+5]; double e[100+5][100+5]; ...