[POJ 1062] 昂贵的聘礼【Dijkstra】

  • 2018-01-03
  • 0
  • 0

Problem:

Time Limit: 1000MS Memory Limit: 10000K

Description

年轻的探险家来到了一个印第安部落里。在那里他和酋长的女儿相爱了,于是便向酋长去求亲。酋长要他用10000个金币作为聘礼才答应把女儿嫁给他。探险家拿不出这么多金币,便请求酋长降低要求。酋长说:"嗯,如果你能够替我弄到大祭司的皮袄,我可以只要8000金币。如果你能够弄来他的水晶球,那么只要5000金币就行了。"探险家就跑到大祭司那里,向他要求皮袄或水晶球,大祭司要他用金币来换,或者替他弄来其他的东西,他可以降低价格。探险家于是又跑到其他地方,其他人也提出了类似的要求,或者直接用金币换,或者找到其他东西就可以降低价格。不过探险家没必要用多样东西去换一样东西,因为不会得到更低的价格。探险家现在很需要你的帮忙,让他用最少的金币娶到自己的心上人。另外他要告诉你的是,在这个部落里,等级观念十分森严。地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。他是一个外来人,所以可以不受这些限制。但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。因此你需要在考虑所有的情况以后给他提供一个最好的方案。
为了方便起见,我们把所有的物品从1开始进行编号,酋长的允诺也看作一个物品,并且编号总是1。每个物品都有对应的价格P,主人的地位等级L,以及一系列的替代品Ti和该替代品所对应的"优惠"Vi。如果两人地位等级差距超过了M,就不能"间接交易"。你必须根据这些数据来计算出探险家最少需要多少金币才能娶到酋长的女儿。

Input

输入第一行是两个整数M,N(1 <= N <= 100),依次表示地位等级差距限制和物品的总数。接下来按照编号从小到大依次给出了N个物品的描述。每个物品的描述开头是三个非负整数P、L、X(X < N),依次表示该物品的价格、主人的地位等级和替代品总数。接下来X行每行包括两个整数T和V,分别表示替代品的编号和"优惠价格"。

Output

输出最少需要的金币数。

Sample Input

1 4
10000 3 2
2 8000
3 5000
1000 2 1
4 200
3000 2 1
4 200
50 2 0

Sample Output

5250

Source

浙江

Solution:

##说句题外话,难得在 POJ 上碰到一道中文题,而且又是一道很好的图论题。##

将物品 1 作为终点,并创建一个虚拟节点“物品 0”作为起点,表示初始状态。

对于每个价格为 P 的物品 i,从 0 -> i 连一条权值为 P 的边,表示从初始状态到拥有物品 i 需要花费 P 个金币。

对于物品 i 的每个价格为 V 的替代品 T,从 T -> i 连一条权值为 V 的边,表示从拥有物品 T 到换得 i 需要花费 V 个金币。

由于等级限制,每次枚举一个物品的主人等级 L,限定只与等级在 L ~ L+M 范围内的人交易,跑 Dijkstra 即可。

Code: O(n3) [192K, 16MS]

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

int M, N, ans;

struct Edge{
	int np, val;
	Edge *nxt;
};

struct Graph{
	Edge *V[105], E[10105];
	int L[105], tope;
	
	inline void clear() {tope = 0, memset(V, 0, sizeof(V));}
	
	inline void addedge(int u, int v, int w){
		E[++tope].np = v, E[tope].val = w;
		E[tope].nxt = V[u], V[u] = &E[tope];
	}
} G;

bool tried[105];
int cost[105];
bool vis[105];

inline int Dijkstra(){
	memset(cost, 0x3f, sizeof(cost)), cost[0] = 0;
	memset(vis, 0, sizeof(vis));
	for(register int i = 0; i <= N; i++){
		int mincost = 101;  // Use an empty number as the beginning of the comparation
		for(register int j = 0; j <= N; j++)
			if(!vis[j] && G.L[j] - G.L[0] <= M && cost[j] < cost[mincost]) mincost = j;
		vis[mincost] = 1;  // Find a object with minimum cost
		if(mincost == 1) return cost[1];  // The explorer finds out the amount of dowry
		for(register Edge *ne = G.V[mincost]; ne; ne = ne->nxt)
			if(G.L[ne->np] >= G.L[0] && G.L[ne->np] - G.L[0] <= M)
				cost[ne->np] = min(cost[ne->np], cost[mincost] + ne->val);  // Update the cost
	}
	return 0x3f3f3f3f;
}

int main(){
	while(scanf("%d%d", &M, &N) != EOF){
		G.clear();
		for(register int i = 1; i <= N; i++){
			int P, X, T;
			scanf("%d%d%d", &P, &G.L[i], &X);
			G.addedge(0, i, P);  // Buy this object directly
			for(register int j = 1; j <= X; j++){
				scanf("%d%d", &T, &P);
				G.addedge(T, i, P);  // Use surrenal to lower the price
			}
		}
		memset(tried, 0, sizeof(tried)), ans = 0x3f3f3f3f;
		for(register int i = 1; i <= N; i++){  // Try to pretend as each level of the owners
			if(tried[G.L[i]] || abs(G.L[i] - G.L[1]) > M) continue;
			tried[G.L[0] = G.L[i]] = 1;
			ans = min(ans, Dijkstra());
		}
		printf("%d\n", ans);
	}
	return 0;
}

评论

还没有任何评论,你来说两句吧



新博客地址:
darkleafin.cf
(该域名已过期且被抢注。。)
darkleafin.github.io


常年不在线的QQ:
49750

不定期更新的GitHub:
https://github.com/Darkleafin


OPEN AT 2017.12.10

如遇到代码不能正常显示的情况,请刷新页面。
Please refresh the page if the code cannot be displayed normally.


发现一个优美的网站:
https://visualgo.net/en
















- Theme by Qzhai