codeforces 730C (二分)

题目链接:点击这里

题意:给出n个点m条边的图,有w个工厂,已知每个工厂的挖掘机数和挖掘机单价。给出q个询问,每次询问要在某一个点获得j个挖掘机并且花费不超过a的最少时间。经过一条边的时间花费是1.

如果不考虑时间因素,那么直接按照单价排序从前往后买挖掘机即可。考虑到时间有二分性质,直接二分时间。首先对询问的点做一遍bfs获得其他点到它的时间,然后二分时间,每次check时从前往后将时间内的挖掘机都买进来判断数量买够时的花费在不在a的范围内即可。这样复杂度就是O(q*m*lgn).

#include <bits/stdc++.h>
using namespace std;
#define maxn 5005
#define maxm maxn<<1
#define INF 1e9

struct node {
    int v, next;
}edge[maxm];
int head[maxn], cnt;
int n, m, w;
struct Q {
    int num, price, id;
    bool operator < (const Q &a) const {
        return price < a.price;
    }
};
vector <Q> gg;

void add_edge (int u, int v) {
    edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;
}

int s, d[maxn];
long long r, cost;
bool vis[maxn];
queue <int> q;

bool ok (int x) {
    long long tot = 0;//花费
    long long sum = 0;//总数
    for (int i = 0; i < w; i++) if (d[gg[i].id] <= x) {
        if (gg[i].num+sum <= r) {
            tot += 1LL*gg[i].num*gg[i].price;
            sum += gg[i].num;
        }
        else {
            tot += (r-sum)*gg[i].price;
            sum = r;
        }
    }
    return sum == r && tot <= cost;
}

void bfs () {
    for (int i = 1; i <= n; i++) d[i] = INF; d[s] = 0;
    memset (vis, 0, sizeof vis); vis[s] = 1;
    while (!q.empty ()) q.pop (); q.push (s);
    while (!q.empty ()) {
        int u = q.front (); q.pop ();
        for (int i = head[u]; i+1; i = edge[i].next) {
            int v = edge[i].v;
            if (vis[v]) continue;
            vis[v] = 1; d[v] = d[u]+1;
            q.push (v);
        }
    }
    int l = 0, r = n;
    long long tmp;//花费
    int Min;
    while (r-l > 1) {
        int mid = (l+r)>>1;
        if (ok (mid)) r = mid;
        else l = mid;
    }
    if (ok (l)) printf ("%d\n", l);
    else if (ok (r)) printf ("%d\n", r);
    else printf ("-1\n");
}

int main () {
    //freopen ("more.in", "r", stdin);
    cin >> n >> m;
    memset (head, -1, sizeof head);
    cnt = 0;
    for (int i = 0; i < m; i++) {
        int u, v;
        scanf ("%d%d", &u, &v);
        add_edge (u ,v);
        add_edge (v, u);
    }
    cin >> w; gg.clear ();
    for (int i = 0; i < w; i++) {
        int c, k, p;
        scanf ("%d%d%d", &c, &k, &p);
        gg.push_back ((Q) {k, p, c});
    }
    sort (gg.begin (), gg.end ());
    int q; cin >> q;
    while (q--) {
        scanf ("%d%lld%lld", &s, &r, &cost);
        bfs ();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值