题目描述:N个电线杆P条线可选,K条线内免费,否则花费免费额度外最长的那一根。
求最小花费
题解:二分答案,模式同最大值最小化。
Check(mid):
建图。
因为mid可能就是结果,故将原图按照边权是否大于mid重新建图,用dijsktra求1到n
的最短路,d[n]即表示所需免费数,与k比较大小,调整l与r。
参考程序:
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#define maxn 2100
using namespace std;
int K;
struct Edge{
int dist,to;
Edge(int dist,int to):dist(dist),to(to){}
bool operator < (const Edge& rhs)const{
return dist>rhs.dist;
}
};
struct Dijsktra{
vector<Edge> G[maxn],G2[maxn];
bool done[maxn];
int d[maxn];
int n;
void init(int n){
this->n=n;
for (int i=0;i<n;i++)G[i].clear();
}
void addedge(int a,int b,int c){
G[a].push_back(Edge(c,b));
G[b].push_back(Edge(c,a));
}
bool Check(int k){
priority_queue<Edge> Q;
memset(done,0,sizeof(done));
memset(d,0x3f,sizeof(d));
Q.push(Edge(0,0));d[0]=0;
while (!Q.empty()){
Edge now=Q.top();Q.pop();
int u=now.to;
if (done[u])continue;
done[u]=true;
for (int i=0;i<G[u].size();i++){
Edge e=G[u][i];
if (d[u]+(e.dist>k?1:0)<d[e.to]){
d[e.to]=d[u]+(e.dist>k?1:0);
if (!done[e.to])Q.push(Edge(d[e.to],e.to));
}
}
}
return d[n-1]<=K;
}
}map;
int main(){
int N,P;
scanf("%d%d%d",&N,&P,&K);
map.init(N);
int r=0;
for (int i=0;i<P;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
a--;b--;
r=max(r,c);
map.addedge(a,b,c);
}
int l=0;r+=2;int limit=r;
while (l<r){
int mid=(l+r)>>1;
if (map.Check(mid))r=mid;
else l=mid+1;
}
printf("%d",(l>limit-2?-1:l));
return 0;
}