题意
有n个点,编号从1到n,有m条边,每条边有一个长度w。
Alice有一艘飞船,Alice可以给它升级很多次(无限),每升级一次需要花费c,升级一次之后飞船单次可飞行距离增加d,可飞行次数增加e。如果飞船需要飞过一条边,就需要满足单次可飞行距离≥这条路的长度同时可飞行次数不为0。
现在Alice在编号为1的点,她的飞船为0级,单次可飞行距离和可飞行次数都为0,请你求出最小的花费使得Alice可以到达n点,如果不能到达n则输出−1。
输入保证图联通,没有自环,没有重边
思路:
就是二分答案,有两个限制条件,用优先队列让边数少的先走,走过的点不再推入。
#include<bits/stdc++.h>
using namespace std;
const int inf = (1<<30);
typedef long long ll;
struct edge
{
ll to,cost;
};
struct node
{
ll dian;
ll bian,maxdis;
friend bool operator < (node n1, node n2)
{
return n1.bian>n2.bian;
}
};
ll n,m,c,d,e,flag = 0;
vector<edge>q[111111];
int vis[111111];
bool judge(ll mid)
{
ll dd = mid*d;
ll ee = mid*e;
memset(vis,0,sizeof(vis));
priority_queue<node>p;
node a;
a.dian = 1;
a.bian = 1;
vis[1] = 1;
a.maxdis = 0;
p.push(a);
while(!p.empty())
{
node now = p.top();
if(now.dian==n)
{
if(now.bian<=ee)
{
flag = 1;
return true;
}
}
p.pop();
for(int i = 0 ; i < q[now.dian].size() ; i ++)
{
node t;
t.bian = now.bian + 1;
t.dian = q[now.dian][i].to;
t.maxdis = max(now.maxdis,q[now.dian][i].cost);
if(t.maxdis<=dd && t.bian<=ee && !vis[t.dian])
{
p.push(t);
vis[t.dian] = 1;
}
}
}
return false;
}
int main()
{
cin >> n >> m;
cin >> c >> d >> e;
for(int i = 1 ; i <= m ; i ++)
{
ll a,b,d;
scanf("%d%d%d",&a,&b,&d);
q[a].push_back(edge{b,d});
q[b].push_back(edge{a,d});
}
ll l = 1,r = 111111,mid,ans;
while(l<=r)
{
mid = (l+r)>>1;
//cout << l << " " << r << " " << mid << endl;
if(judge(mid))
{
r = mid - 1;
ans = mid;
}
else
{
l = mid + 1;
}
}
if(flag)
cout << ans*c << endl;
else
cout << -1 << endl;
return 0;
}