给出一张图,多次询问点a到b的最大携带货物量i为多少,假设a到b距离为k,则花费金额为i^1+i^2...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 */