POJ - 1062 有限制的最短路

題目鏈接
題意
n個人每人有一個物品,每個物品可以直接買,也可以通過其他物品抵押加上少量的錢買,每個人有一個等級,經過若干次交換購買的人中的最大等級差不能超過m。求要得到第一件物品的最少花費是多少?
思路
如果沒有等級約束就是一個最短路的模板題,根據a物品加w個金幣換到b物品,可以建立一條有向邊a->b,cost w。然後直接用最短路即可,但是因爲有了約束,不能直接調用。考慮題目的要求是要換到編號爲1的物品,所以能交換到1的人羣中,等級差異不能超過m,並且這個等級範圍要包括1的等級,因題目範圍較小,直接枚舉區間,多次調用dijkstra取最小值。
還有一個小技巧,題中沒有規定起點,我們可以假設0爲起點,從0到每個頂點建立一條邊,邊的權值就是直接購買該物品的價格。

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
#define INF 0x3f3f3f3f
#define pr pair<int, int>
const int maxn = 1e5 + 7;
typedef long long ll;
int head[maxn], to[maxn<<1], nex[maxn<<1], edge[maxn<<1], cnt;
int n, m;
void init() {
    memset(head, -1, sizeof(head));
    cnt = 0;
}
void add(int x, int y, int z) {
    to[cnt] = y;
    edge[cnt] = z;
    nex[cnt] = head[x];
    head[x] = cnt++;
}
int d[maxn], p[maxn];
bool final[maxn];
void dijkstra(int l, int r)
{
	memset(final, 0, sizeof(final));
	memset(d, INF, sizeof(d));
	priority_queue<pr, vector<pr>, greater<pr> > q;
	q.push(make_pair(0, 0));//first是length,second是頂點
	d[0] = 0;
	while (!q.empty())
	{
		int u = q.top().second;
		q.pop();
		final[u] = true;
		for (int i = head[u]; ~i; i = nex[i])
		{
			int v = to[i];
			int len = edge[i];
			if(!final[v] && d[v] > d[u] + len && p[v] >= l && p[v] <= r)
			{
				d[v] = d[u] + len;
				q.push(make_pair(d[v], v));
			}
		}
	}
}
int main()
{
    init();
    scanf("%d %d", &m, &n);
    for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d%d%d", &d[i], &p[i], &x);
        for (int j = 1; j <= x; j++) {
            int a, b;
            scanf("%d%d", &a, &b);
            add(a, i, b);
        }
    }
    for (int i = 1; i <= n; i++)
        add(0, i, d[i]);
    p[0] = p[1];
    int ans = INF;
    for (int i = max(0, p[1] - m); i - p[1] <= m; i++) {
        dijkstra(i, min(i + m, p[1] + m));
        ans = min(d[1], ans);
    }
    printf("%d\n", ans);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章