昂贵的聘礼 _POJ-1062(思维+枚举+最短路)(Dijkstra)

去POJ AC题目,拿奖金你也可以娶公主

先看题:

                                                   昂贵的聘礼

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 60385 Accepted: 18260

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
  • 一堆训练题里面唯一一道中文题。。。好不容易是个能看懂的,还贼**难,读了几遍读不懂,唉,还不如英文题呢
  • 果然这是一个最短路问题,每个物品就是一个点,两个物品交易所需要的额外的钱数就是两点之间的距离,建图还算比较简单,难点请往下看↓↓↓

  • 最难的是这个落后的民族居然还存在着等级限制,woc,等级超过限制的间接交易竟然也不行,我TM。。。这不是等级歧视吗?应该去消灭他们

  • 那么这个题怎么求解呢?我也是懵逼加懵逼,只能去CSDN上找了一下大神的解释,这有一篇blog解释的很详细  我就不在关公面前耍大刀了 ,真卑微   Orz

  • 反正就是枚举就对了,可以去枚举等级限制区间,也可以去枚举每一个点来检测是否合格,最后再带上Dijkstra的板子

  • 附上两种代码:仅供参考

 

枚举每一个点,判断是否合格:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
const int mm=105;

int map[mm][mm];
int dis[mm];
int jia[mm];
int lv[mm];
int book[mm];
int m,n,x,t,v;

int dijie(){
	for(int i=1;i<=n;i++)
		dis[i]=jia[i]; 
	for(int i=1;i<=n;i++){
		int mint=inf;
		int u;
		for(int j=1;j<=n;j++){
			if(book[j]==0&&dis[j]<mint){
				mint=dis[j];
				u=j;
			}
		}
		book[u]=1;
		for(int j=1;j<=n;j++){
			if(book[j]==0&&dis[j]>dis[u]+map[u][j])
				dis[j]=dis[u]+map[u][j];
		}
	} 
//	for(int i=1;i<=n;i++)
//		cout<<dis[i]<<' ';
	return dis[1];
}

int main()
{
	scanf("%d%d",&m,&n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			map[i][j]=inf;
			
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&jia[i],&lv[i],&x);
		while(x--){
			scanf("%d%d",&t,&v);
			map[t][i]=v;//空手到获得 
		}
	}
	for(int i=1;i<=n;i++)
		map[0][i]=jia[i];
	
//	for(int i=1;i<=n;i++){
//		for(int j=1;j<=n;j++)
//			cout<<map[i][j]<<' ';
//		cout<<endl;
//	}	
	
	int res=inf; 
	for(int i=1;i<=n;i++){
		int pp=lv[i];//当前最高等级 
		for(int j=1;j<=n;j++){
			if(lv[j]-pp>m||pp>lv[j])
				book[j]=1;//不能作为中转点进行松弛 
			else book[j]=0;//下一波的恢复 
		}
		int temp=dijie();
		res=min(res,temp);
	}
	printf("%d\n",res);
	return 0;
}

枚举等级限制区间:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int mm=105;

int dis[mm];//用第i个物品换公主需要添加的money 
int book[mm];
int map[mm][mm];//i换j的额外消费 
int lv[mm],val[mm];
int vis[mm];//能否交易
int n,m,v,t,x;

int dijie(){
	memset(book,0,sizeof(book));
	for(int i=1;i<=n;i++)
		dis[i]=inf;//没有还输入交换所需的钱数 
	dis[1]=0;
	
	for(int i=1;i<=n;i++){
		int mint=inf;
		int u;
		for(int j=1;j<=n;j++)
			if(dis[j]<mint&&book[j]==0&&vis[i]==1){
				mint=dis[j];
				u=j;
			}
		book[u]=1;
		for(int j=1;j<=n;j++){
			if(book[j]==0&&vis[j]==1&&dis[u]+map[u][j]<dis[j])
				dis[j]=dis[u]+map[u][j]; 
		}
	}
		
	int mint=inf;
	for(int i=1;i<=n;i++){
		dis[i]+=val[i];// 本金加上添加的money 即最终money 
		mint=min(mint,dis[i]);
	}
	return mint;	
}

int main()
{
	cin>>m>>n;
	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++){
		cin>>val[i]>>lv[i]>>x;
		while(x--){
			cin>>t>>v;
			map[i][t]=v;
		}
	}
	int klv=lv[1];//酋长的等级 
	int res=inf;
	for(int i=0;i<=m;i++){//枚举等级差,不要高于限制 
		memset(vis,0,sizeof(vis));
		for(int j=1;j<=n;j++){//枚举所有人,找到满足条件的 
			//例如酋长等级是5,限制为2,则等级区间可以是[3,5][4,6][5,7] 
			if(lv[j]>=klv-m+i&&lv[j]<=klv+i)//枚举区间 
				vis[j]=1;
		}
		res=min(res,dijie());
	}
	cout<<res;
	return 0;
 } 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值