2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest C. Bulmart 详解
C. Bulmart
题目大意:
有n个城市,m条路,input:m个x,y表示x城市和y城市相连
有w个商店,iput:w个c,n,p表示第i个商店所在的城市,商店的储货以及该商店货物价格
有q个查询,input:q个g,r,a询问运送到城市g,r个商品,不超过a元成本的最小时间是多少?
从一个城市到另一个城市需要时间“1”,所需总共时间即为最后一个到达的时间。
大佬解答:
一眼题,二分最短路小蒟蒻瑟瑟发抖
思维:
最小时间是建立在路径最短的情况下,那么就比较容易想到最短路和bfs;
不超过a元的最小时间可能一下比较难想,但是还是可以联想到二分查找的;
check的过程就是先将商品按价格排序,保证check的方案是成本最小的,符合小于a元成本的;
然后时间为mid每次遍历一遍超市数组,距离小于等于mid的商店均可以送达;
#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
#pragma warning (disable:4996)
typedef long long int LL;
vector<int> E[5100];
bool vis[5100];
int w, g, tail, head, n;
LL r, a, dis[5100];
struct City
{
int city;
int step;
}Edge[11000];
struct Shop
{
int city;
LL num;
LL price;
}shop[5100];
bool cmp(Shop a, Shop b)
{
return a.price < b.price;
}
bool check(LL mid)
{
LL need = r, now = 0;
for (int i = 1; i <= w; i++)
{
if (dis[shop[i].city] == n)
continue;
if (dis[shop[i].city] <= mid)
{
if (need > shop[i].num)
{
need -= shop[i].num;
now += LL(shop[i].num)*shop[i].price;
}
else
{
now += LL(need) * shop[i].price;
need = 0;
if (now <= a)
return true;
else
return false;
}
if (now >= a)
return false;
}
}
return false;
}
int main()
{
LL m;
int u, v, q;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
scanf("%d%d", &u, &v);
E[u].push_back(v);
E[v].push_back(u);
}
scanf("%d", &w);
for (int i = 1; i <= w; i++)
cin >> shop[i].city >> shop[i].num >> shop[i].price;
sort(shop + 1, shop + 1 + w, cmp);
scanf("%d", &q);
while (q--)
{
cin >> g >> r >> a;
for (int i = 0; i <= n; i++)
dis[i] = n, vis[i] = false;
head = tail = 0;
Edge[tail].city = g;
Edge[tail].step = 0;
tail++; vis[g] = true;
while (head < tail)
{
for (int k = 0; k < E[Edge[head].city].size(); k++)
{
int v = E[Edge[head].city][k];
if (vis[v])
continue;
vis[v] = true;
Edge[tail].city = v;
Edge[tail].step = Edge[head].step + 1;
tail++;
}
head++;
}
for (int i = 0; i < tail; i++)
dis[Edge[i].city] = Edge[i].step;
LL left = 0, right = n, mid, ans = n;
while (left <= right)
{
mid = (left + right) / 2;
if (check(mid))
{
ans = min(LL(n), mid);
right = mid - 1;
}
else
left = mid + 1;
}
if (ans == n)
printf("-1\n");
else
cout << ans << '\n';
}
}