Telephone Lines
https://vjudge.net/problem/12427/origin
题意:有n个点m条边,每条边为双向且有一个权值,最多可以让k条边的权值变为0,现要最小化从n号点到1号点经过的边权的最大值
思路1:首先设经过的边权的最大值为mid,我们二分这个mid值,mid值大时n到1的路径一定包含mid值小的路径,即满足单调性,所以问题转化为是否存在一种方案使得边权最大值小于等于mid(可以让k条边的边权置0)
我们可以将所有边权大于mid的边长度设置为1,其余的设置为0,这样就可以变为跑01最短路,看最短路长度是否小于等于k(小于等于k时便可以把这些边权大于mid的边的边权置0,即当前mid值满足题意)
01最短路解法:类似用优先队列跑BFS,只不过因为边权只有0和1,这样可以改成用双端队列,如果边权是0就将扩展点加入队首,否则加入队尾,每次拿出队首的点进行扩展,可以保证每次拿出来的都是距离最小的点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<deque>
#define MAXN 1005
#define MAXM 10005
#define INF 0x3f3f3f3f
using namespace std;
int head[MAXN],tot;
struct E
{
int u,v,w;
}e[MAXM];
struct edge
{
int v,w,nxt;
}edg[MAXM << 1];
inline void addedg(int u,int v,int w)
{
edg[tot].v = v;
edg[tot].w = w;
edg[tot].nxt = head[u];
head[u] = tot++;
}
int n,m,k;
bool vis[MAXN];
struct node
{
int u,w;
node(){}
node(int u,int w):u(u),w(w){}
}nod;
deque<node> qu;
inline void init()
{
memset(head,-1,sizeof(int)*(n+1));
memset(vis,false,sizeof(bool)*(n+1));
tot = 0;
while(!qu.empty())
qu.pop_front();
}
inline bool check(int x)
{
init();
int u,v,w;
for(int i = 1;i <= m;++i)
{
if(e[i].w > x)
w = 1;
else
w = 0;
addedg(e[i].u,e[i].v,w);
addedg(e[i].v,e[i].u,w);
}
qu.push_front(node(n,0));
while(!qu.empty())
{
nod = qu.front();
qu.pop_front();
u = nod.u,w = nod.w;
if(u == 1)
{
if(w <= k)
return true;
else
return false;
}
if(vis[u])
continue;
vis[u] = 1;
for(int i = head[u];i != -1;i = edg[i].nxt)
{
v = edg[i].v;
if(!vis[v])
{
if(edg[i].w == 0)
qu.push_front(node(v,w));
else
qu.push_back(node(v,w+1));
}
}
}
return false;
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&k))
{
int l = 0,r = 0,mid,ans = -1;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
r = max(r,e[i].w);
}
while(l <= r)
{
mid = (l+r) >> 1;
if(check(mid))
{
ans = mid;
r = mid-1;
}
else
l = mid+1;
}
printf("%d\n",ans);
}
return 0;
}
思路二:
https://blog.csdn.net/xing_mo/article/details/103925627