题目链接
P1948 [USACO08JAN]电话线Telephone Lines
分析
- 简单观察题目,易得本题是求解最小最大值,宜用二分!!!
- 证明:当存在一种有效路径时,这种路径会包含一种更小代价的有效路径(即可能是存在更小的最大值)
- 二分思路:在(l,r)区间内寻找符合条件的最大值,l=0,r=最大边权值
- 具体判断:
- 将题目转化为判定性问题
- 对边进行处理,E[].dis>mid 则此边为1,否则为0
- 进行dijkstra求解
- 若Dis[N]=inf,则不存在通路,返回false;若Dis[N]<K则返回true
具体代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1000010;
typedef pair<int,int>node;
struct Edge
{
int dis,next,to;
} E[maxn/2];
int Dis[1010],Head[1010],num_Edge,vis[1010];
int N,P,K,mid,MAX_DIS;
inline int Read(void)
{
int w=0,x=0;
char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
return w?-x:x;
}
inline void Add_Edge(int u,int v,int d)
{
E[++num_Edge].dis =d;
E[num_Edge].to =v;
E[num_Edge].next =Head[u];
Head[u]=num_Edge;
}
inline void Set()
{
memset(vis,0,sizeof(vis));
for(int i=1; i<=N; ++i)
Dis[i]=2147483247;
Dis[1]=0;
}
inline int Dijkstra(void)
{
Set();
priority_queue<node,vector<node>,greater<node> >Q;
Q.push(make_pair(0,1));
while(!Q.empty() )
{
int u=Q.top().second;
Q.pop() ;
if(vis[u]) continue;
for(int i=Head[u]; i; i=E[i].next )
{
int v=E[i].to,dis=E[i].dis>mid?1:0;
if(Dis[v]>Dis[u]+dis)
{
Dis[v]=Dis[u]+dis;
if(!vis[v])
Q.push(make_pair(Dis[v],v));
}
}
}
return Dis[N];
}
int main(void)
{
N=Read(),P=Read(),K=Read();
for(int i=1; i<=P; ++i)
{
int u=Read(),v=Read(),d=Read();
MAX_DIS=max(MAX_DIS,d);
Add_Edge(u,v,d);
Add_Edge(v,u,d);
}
int l=0,r=MAX_DIS;
while(l<r)
{
mid=(l+r)/2;
if(Dijkstra()>K) l=mid+1;
else r=mid;
}
if(l==MAX_DIS) printf("-1\n");
else printf("%d\n",r);
return 0;
}