2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest C. Bulmart 详解

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';
 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值