POJ 1062 解题报告

这道题实际上是单源最短路径问题,每条边(从一个物品到替换它的物品之间)都有一个权值,即cost。问题是求从第一个物品到其他所有物品的最低开销,这个开销除了路径总cost外还得包含这个物品的价值(因为这个物品是最终替代第一个物品的物品)。

明白了上述这些后,自然而然的想法就是应用最短路径算法,比如Dijkstra,SPFA或是Bellman-Ford。

这个问题的有意思的地方在于它还对可选的物品有个限制,即从第一个物品到每个物品的路径上的物品的Level之差必须在M以内。一个简单的处理方法就是做枚举。假设第一个物品的Level是L(准确的说是拿物品的人的Level,而第一个物品是必须“交易”的,无论选第一个物品还是选它的替代品)。那么Level的最低值low范围为[L - M, L]。相应的Level最高值high为low + M。所以需要对low,high的限定范围做个枚举,跑这个多次单源最短路径,然后求出所有这些中的最小开销。

事实证明Dijkstra是个非常高效的方法,即使在实现得很烂的情况下(如本题的实现没有用priority_queue,所以每步选min的时间都是O(N))。时间仍然是0ms。

可以参见http://poj.org/showmessage?message_id=183977。代码实现得很清楚。

1062Accepted168K0MSC++3031B
/* 
ID: thestor1 
LANG: C++ 
TASK: poj1062 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

class Substitute
{
public:
	int T, V;
	Substitute() {}
	Substitute(int T, int V) : T(T), V(V) {}
};

class Item
{
public:
	int P, L, minP;
	vector<Substitute> substitutes;
	Item() : minP(-1) {}
	Item(int P, int L) : P(P), L(L), minP(-1) {}
};

int dfs(vector<Item> &items, int t, int low, int high, const int M)
{
	if (items[t].minP >= 0)
	{
		return items[t].minP;
	}

	int minP = items[t].P;
	for (int i = 0; i < items[t].substitutes.size(); ++i)
	{
		if (low <= items[items[t].substitutes[i].T].L && items[items[t].substitutes[i].T].L <= high)
		{
			// substitutes[i].T, substitutes[i].V
			int price = dfs(items, items[t].substitutes[i].T, max(low, items[items[t].substitutes[i].T].L - M), min(high, items[items[t].substitutes[i].T].L + M), M);
			if (price + items[t].substitutes[i].V < minP)
			{
				minP = price + items[t].substitutes[i].V;
			}
		}
	}
	items[t].minP = minP;
	return minP;
}

int dijkstra(vector<Item> &items, const int low, const int high, vector<bool> &visited, vector<int> &dis)
{
	int N = items.size();
	for (int i = 0; i < N; ++i)
	{
		if (items[i].L < low || items[i].L > high)
		{
			visited[i] = true;
		}
		else
		{
			visited[i] = false;
		}
		dis[i] = INT_MAX;
	}

	dis[0] = 0;

	for (int i = 0; i < N; ++i)
	{
		int mindis = INT_MAX, minu = -1;
		for (int j = 0; j < N; ++j)
		{
			if (!visited[j] && dis[j] < mindis)
			{
				mindis = dis[j];
				minu = j;
			}
		}
		if (mindis == INT_MAX)
		{
			break;
		}

		visited[minu] = true;
		for (int j = 0; j < items[minu].substitutes.size(); ++j)
		{
			Substitute substitute = items[minu].substitutes[j];
			if (!visited[substitute.T] && mindis < INT_MAX - substitute.V && mindis + substitute.V < dis[substitute.T])
			{
				dis[substitute.T] = mindis + substitute.V;
			}
		}
	}

	int minP = INT_MAX;
	for (int i = 0; i < N; ++i)
	{
		if (dis[i] < INT_MAX - items[i].P && dis[i] + items[i].P < minP)
		{
			minP = dis[i] + items[i].P;
		}
	}
	return minP;
}



int main()
{
	int M, N;
	scanf("%d%d", &M, &N);
	vector<Item> items(N);
	int X, T, V;
	for (int i = 0; i < N; ++i)
	{
		scanf("%d%d%d", &items[i].P, &items[i].L, &X);
		for (int j = 0; j < X; ++j)
		{
			scanf("%d%d", &T, &V);
			T--;
			items[i].substitutes.push_back(Substitute(T, V));
		}
	}

	int minP = INT_MAX;
	vector<bool> visited(N);
	vector<int> dis(N);
	for (int low = items[0].L - M; low <= items[0].L; ++low)
	{
		int high = low + M;
		int price = dijkstra(items, low, high, visited, dis);
		if (price < minP)
		{
			minP = price;
		}
	}
	
	printf("%d\n", minP);

	return 0;  
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值