链接: poj3662
题意:
这几天在做二分的题,开始看到怎么是图论的题,吓我一跳;
不过还好,经过思索,发现是个二分+最短路的题;
题上给你 n 个点,要你从 1 连接电话线路到 n;
给你 p 条路,有的可以不选;
给你一个 k,表示有 k 条路线可以不用给钱;
上面那个 k 是最坑的,题上说的时候完全看不懂。。
让你求这些路径中除掉 k 条路之后的最长那条的最小值。。
理解:
开始蒙了,不知道怎么求,根本没从二分这个角度去想。。。
之后想了下二分,发现可以;
二分答案,但不知道怎么判断 k;
最短路只能找出路径的长短;
之后看了大神的见解,发现可以把路径变换下;
于是根据答案来建图;
怎么建:大于答案的就是1,小于的是0;
之后得到最短路的值,判断k 与这个值得关系;
这样就阔以求了。。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <string>
#include <set>
#include <cmath>
#include <stack>
using namespace std;
#define maxn 100100
#define x first
#define y second
#define ll long long
#define P pair<int, int>
#define INF 1e9
struct node
{
int a, b, c;
};
int n, p, k;
vector<node> ve;
vector<P> vec[maxn/100 + 10];
int d[maxn/100 + 10];
void build(int m) //傻逼的建了这么多次图。。。
{
for (int i = 0; i < p; ++i)
{
if (ve[i].c < m)
{
vec[ve[i].a].push_back(P(0, ve[i].b));
vec[ve[i].b].push_back(P(0, ve[i].a));
}
else
{
vec[ve[i].a].push_back(P(1, ve[i].b));
vec[ve[i].b].push_back(P(1, ve[i].a));
}
}
}
int dij() //求最短路
{
fill(d, d + n + 1, maxn); //下标从 1 开始啊。。。
priority_queue<P, vector<P>, greater<P> > que;
que.push(P(0, 1));
d[1] = 0;
while(!que.empty())
{
P pa = que.top();
que.pop();
if (d[pa.y] < pa.x) continue;
for (int i = 0; i < vec[pa.y].size(); ++i)
{
P t = vec[pa.y][i];
if (d[t.y] > d[pa.y] + t.x)
{
d[t.y] = d[pa.y] + t.x;
que.push(P(d[t.y], t.y));
}
}
}
return d[n];
}
int main()
{
scanf("%d%d%d", &n, &p, &k);
for (int i = 0; i < p; ++i)
{
node num;
scanf("%d%d%d", &num.a, &num.b, &num.c);
ve.push_back(num);
}
ll lb = 0, rb = (ll)0x7fffffff + 10;//用这个要爆int啊。。
while(rb - lb > 1)
{
for (int i = 0; i <= n; ++i)
vec[i].clear();
ll mid = (lb + rb) / 2;
build(mid);
if (dij() > k) //mid取小了
{
lb = mid;
}
else
{
rb = mid;
}
}
if (lb > (ll)0x7fffffff) lb = -1;//找不到的情况
printf("%lld\n", lb);
return 0;
}