https://ac.nowcoder.com/acm/problem/213992
给出一张图,多次询问点a到b的最大携带货物量i为多少,假设a到b距离为k,则花费金额为i1+i2…i^k,要求是花费不能大于上限b。
首先最短路是显然的。注意到地图的数据范围n,m (1≤n≤100, m≤(n(n+1)/2)),查询次数Q (1≤Q≤10^5),地图范围很小而需要频繁的询问不同点之间的距离,显然是floyd。至于寻找最大携带货物量用二分查找即可。
注意,判断上式是否大于b,如果用我这种写法需要在大于b的时候及时return false,否则会爆数据范围。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=110;
const ll inf=0x3f3f3f;
int mp[maxn][maxn];
int n, m, q;
void floyd(int n)
{
for (int k = 1; k <= n;k++)
for(int i = 1;i <= n;i++)
for (int j = 1; j <= n;j++)
if(mp[i][j] > mp[i][k] + mp[k][j])
{
mp[i][j] = mp[i][k] + mp[k][j];
}
}
ll quick_pow(int a,int b)
{
ll ans = 1,base = a;
while(b)
{
if(b&1)
ans = ans * base;
base = base * base;
b >>= 1;
}
return ans;
}
bool work(int num,int len,ll up)
{
ll ans = 0;
for(int i = 1;i <= len;i++)
{
ans += quick_pow(num,i);
if(ans > up)
return false;
}
return true;
}
int main()
{
scanf("%d%d",&n,&m);
memset(mp,inf,sizeof(mp));
for (int i = 1;i <= m;i++)
{
int u,v;
scanf("%d%d", &u, &v);
mp[u][v] = mp[v][u] = 1;
}
floyd(n);
scanf("%d", &q);
for(int i = 1;i <= q;i++)
{
int u,v,up;
scanf("%d%d%d", &u, &v, &up);
int l = 1, r = up+1;
int len = mp[u][v];
int ans;
while(l < r)
{
int mid = (l + r)/2;
if(work(mid,len,up))
l = mid + 1;
else
r = mid;
}
cout << l-1 << endl;
}
return 0;
}
/*
5 4
1 2
2 3
3 4
3 5
4
1 5 15
1 5 13
1 3 7
1 3 5
*/