您的位置:首页 > 其它

poj1062 昂贵的聘礼(Dijkstra+枚举等级处理)

2013-12-10 13:45 281 查看
昂贵的聘礼

Time Limit: 1000MSMemory Limit: 10000K
Total Submissions: 33464Accepted: 9533
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
本题题意应该没什么问题。
算法:最短路Dijkstra
但是由于本题加了一个等级限制,所以处理起来感觉像是无头的苍蝇,没有思绪。看了别人的报告后,可以用下面的处理方式。
思路:Dijkstra+枚举等级
等级的限制让我们在处理Dijkstra的的时候不得不加上一个条件,就是在计算单源最短路的时候,处理的节点都落在一个区间[a,b]内。
有题目易知,源点为1,也就是说所有的方案(路径)都会经过1,设1号节点的等级为lever,那么我们很容得到一个节点区间[lever-m,lever+m]。这只是一个区间并不准备,
因为在[lever-m,lever+m]中会存在等级超过m的两个节点。怎么处理呢?
自己想一想很容易知道,我很将[lever-m,lever+m]打碎为多个连续的,且长度为m的小区间即可。
即:[lever-m,lever]  ,    [lever-m+1,lever+1]   ,   [lever-m+2,lever+2]   ,   [lever-m+3,lever+3]   ,   [lever-m+4,lever+4]........[lever,lever+m];
这m个子区间的并集属于大区间[lever-m,lever+m],每个小区间做一次单源最短路,答案就是这m个小区中最小的那个,具体看代码。
1 //最短路径——Dijkstra算法
2 //此题的关键在于等级限制的处理,最好的办法是采用枚举,即假设酋长等级为5,等级限制为2,那么需要枚举等级从3~5,4~6,5~7
3 //从满足改等级范围的结点组成的子图中用Dijkstra来算出最短路径
4 //小结,通过枚举的方式可以消除一些图与图之间的限制

本题心得与体会:一开始还感觉自己单源最短路掌握还不错,通过这道题又让我发现了我的不足。
第一:对Dijkstra算法没有很好的理解,具体就是原理上的理解不深刻,因此导致在实现上磕磕绊绊(以前总是套模版,模版不是什么好东西,一定要理解,手动才是王道)
第二:考察对算法理解程度如何的方式,一方面是看敲代码的熟练程度,其次就是,对于算法的每一步的意义是否清楚,理解,最后就是,对于该算法的最终状态是否一目了然,
也就是用个这个算法,最后也变成是什么样子,达到什么样的状态(与定义的一些变量的值什么等等)。从这点上来说,我还有一定的差距。
/*
@author : liuwen
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cmath>
using namespace std;
const int maxn=105;
const int inf=0x7ffffff;
int dist[maxn],p[maxn],Map[maxn][maxn],Rank[maxn],value[maxn];
int n,m;
void  initial_map()
{
memset(Rank,0,sizeof(Rank)); //Rank[i]表示物品i的等级
memset(value,0,sizeof(value)); //物品i的价格
for(int i=1;i<=n;i++){          //边上初始化
for(int j=1;j<=n;j++){
if(i==j)    Map[i][j]=0;
else    Map[i][j]=inf;
}
}
for(int i=1;i<=n;i++){ //输入
int val,lev,x;
scanf("%d%d%d",&val,&lev,&x);
value[i]=val;
Rank[i]=lev;
while(x--){
int u,d;
scanf("%d%d",&u,&d);
Map[i][u]=min(d,Map[i][u]); //有重边
}
}
}
void Dijkstra(int low_lever,int up_lever)  //在源点为1,区间[low_lever,up_lever]上的Dijkstra
{
memset(p,0,sizeof(p));  //p[i]=1表示节点i为已经选择,否则为没有选择
for(int i=1;i<=n;i++){
if(Rank[i]>up_lever||Rank[i]<low_lever){//这一点与模版Dijkstra有区别,由于有等级的限制,区间外也都在集合Va中(已经选择的集合中)
p[i]=1;
}
}
for(int i=1;i<=n;i++)   dist[i]=inf;
dist[1]=0;
int i,j,k,Min;
for(i=1;i<=n-1;i++){
Min=inf;
k=0;
for(j=1;j<=n;j++){
if(!p[j]&&dist[j]<Min){
Min=dist[j];
k=j;
}
}
if(k==0)    return;
p[k]=1;
for(j=1;j<=n;j++){
if(!p[j]&&Map[k][j]!=inf&&dist[j]>dist[k]+Map[k][j]){
dist[j]=dist[k]+Map[k][j];
}
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&m,&n)==2){
initial_map();
int min_val=inf;//每种交换选择必须包含1,因此最起码的情况应该是(lev-m,lev+m),但这个区间很有可能包含等级相差超过m的情况
for(int i=Rank[1]-m;i<=Rank[1];i++){ //故,枚举等级
Dijkstra(i,i+m);  //{Rank[1]-m,Rank[1]},{Rank[1]-m+1,Rank[1]+1},{Rank[1]-m+2,Rank[1]+2}...{Rank[1],Rank[1]+m}
for(int j=1;j<=n;j++){
min_val=min(min_val,dist[j]+value[j]);
}
}
printf("%d\n",min_val);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: