Travel Expense 最短路,二分

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
*/

猜你喜欢

转载自blog.csdn.net/qq_42937838/article/details/110069106