nyoj-307 宝物【dp+贪心】

原创 2015年07月09日 09:42:28

宝物

时间限制:1000 ms  |  内存限制:65535 KB
难度:6
描述

传说HMH大沙漠中有一个迷宫,里面藏有许多宝物。迷宫里可能有N个藏宝地点,用1到N标记。藏宝地点之间最多有一条通路相连。标记1为迷宫的进出口。

某天,Dr.Kong找到了迷宫的地图,他已经知道其中K(1<=K<=N)个不同的地点真的藏有宝物。Dr.Kong决定让他的机器人卡多去探险。卡多在经过某个藏宝地点时可能会拿走宝物。但它每拿走一个藏宝地点的宝物后,它的载重量就会增加W。迷宫中的通路不是平坦的,到处都是陷阱。假设每条通路都有一个危险度,其值与通过此路的载重量成正比。

机器人卡多进入迷宫时,它的载重量为0。只有当卡多携带宝物的载重量不大于某个通路的危险度时,它才能顺利通过此条道路,否则就会掉入陷阱,不能出来。

Dr.Kong希望他的机器人卡多尽量多的带出宝物,当然他更希望卡多最后能从标记1的地点走出去。

请你编写程序,帮助Dr.Kong计算一下,卡多最多能带出多少个藏宝地点的宝物。

输入
有多组测试数据,以EOF为输入结束的标志
第1行: N M K W
接下来有K行, 每行一个整数,表示藏有宝物的地点标号。
再接下来有M行,每行三个整数X,Y,Z,表示地点X与地点Y之间有一条危险度为Z的通路。
1 ≤ N ≤ 8000 1 ≤ K ≤ N 1 ≤ M ≤ 15000 1 ≤ W, Z ≤ 10000
数据保证所有的地点之间都是有道路可以到达的。
提示:机器人卡多经过一个藏宝地点时可以不拿走宝物, 而且同一个藏宝地点可以经过多次。
输出
输出有一个整数, 表示卡多最多能带出的宝物的堆数。
样例输入
6 7 5 1
1
2
3
4
5
1 2 3
3 6 2
6 2 10
2 4 1
5 1 1
4 5 1
1 6 1
样例输出
4

我最开始想的是用搜索解决,但是数据量太逼大了。所以果断放弃。

分析题目:

(1)每个藏有宝藏的节点你要保证拿了之后能回到1节点。

(2)尽快能的多拿


所以我想用动态规划来处理得到:每个节点到1节点路径的危险度限制最大是多少。

限制是由路径中最小的那条边来表示。maxPass[u]实质就是记录从1->u权值最小的边。对于maxPass[v]就只记录限制最大的情况。

所以的状态转移方程:maxPass[v]=findMax(maxPass[v],findMin(maxPass[u],z)); 写起来很像spfa额。。。。Orz


接下来就是进行排序,用贪心的思想去多多的拿取。还是在代码中理解吧。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#define Max_V 8100
#define inf 0x3f3f3f3f
using namespace std;
int n,m,k,w;
struct Edge{
	int x,y,z;
};
vector<Edge> g;
bool have[Max_V];//标记该节点是否有宝藏
int maxPass[Max_V];//<span style="font-size: 13.3333339691162px;">每个节点到1节点路径的危险度限制最大是多少</span>
int ik[Max_V];//有效的宝藏点
int p[Max_V];//贪心用的数组
int findMax(int a,int b)
{
	return a>b?a:b;
}
int findMin(int a,int b)
{
	return a>b?b:a;
}
void init()
{
	g.clear();
	memset(have,0,sizeof(have));
}
void add_edge(int x,int y,int z)
{//无向图
	g.push_back((Edge){x,y,z});
	g.push_back((Edge){y,x,z});
}
int cmp(const void *a,const void *b)
{
	return *(int *)a-*(int *)b;
}
int find_way()
{//动态规划找到每个节点到1节点<span style="font-size: 13.3333339691162px;">路径的危险度限制最大是多少</span>
	memset(maxPass,0,sizeof(maxPass));
	maxPass[1]=inf;
	bool flag=true;
	int u,v,z;
	while(flag)
	{
		flag=false;//当遍历所有边都没有maxPass数组更新时,说明动规结束
		for(int i=0;i<g.size();i++)
		{
			u=g[i].x;v=g[i].y;z=g[i].z;
			int t=maxPass[v];
			maxPass[v]=findMax(maxPass[v],findMin(maxPass[u],z));
			if (maxPass[v]!=t)//如果有一个节点的maxPass数组有更新,那么这个节点就可能去更新其它节点。所以动规不终止
				flag=true;
		}
	}
	int count=0;
	for(int j=1;j<=n;j++)
		if(have[j]&&maxPass[j]>=w)//将藏有宝藏的节点记录
			ik[count++]=maxPass[j];
	return count;
}
int solve()
{
	int mk=find_way();
	p[0]=1;
	qsort(ik,mk,sizeof(int),cmp);//排序后贪心
	for(int i=1;i<mk;i++)
	{
		if(ik[i]>=p[i-1]*w+w)
			p[i]=p[i-1]+1;
		else p[i]=p[i-1];
	}
	return p[mk-1];
}
int main()
{
	int i;
	while(~scanf("%d%d%d%d",&n,&m,&k,&w))
	{
		init();
		int loc;
		for(i=0;i<k;i++)
		{
			scanf("%d",&loc);
			have[loc]=1;
		}
		int x,y,z;
		for(i=0;i<m;i++)
		{
			scanf("%d%d%d",&x,&y,&z);
			add_edge(x,y,z);
		}
		printf("%d\n",solve());
	}
	return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

nyoj 单调递增最长子序列(贪心||DP)

单调递增最长子序列 描述 求一个字符串的最长递增子序列的长度 如:dabdbf最长递增子序列就是abdf,长度为4 输入第一行一个整数0 随后的n行,每行有一个字符串,该字符串的长度不会超过1000...

nyoj 49 开心的小明 【dp&&贪心】

 开心的小明 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 小明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他...

nyoj 307(最短路变形)

解题思路:这道题和上一道题一样,也是最短路的变形,我之前的想法是二分答案,然后再dp去判断是否可以满足要求,但发现这样子的话会存在问题:因为一条路可能走多次,就无法保证其后效性。 看了别人的思路:先...

简单的DP运用+贪心算法

  • 2006年02月23日 09:05
  • 484B
  • 下载

nyoj 71 独木舟上的旅行 【贪心&&简单】

 独木舟上的旅行 时间限制:3000 ms  |  内存限制:65535 KB 难度:2 描述 进行一次独木舟的旅行活动,独木舟可以在港口租到,并且之间没有区别。一条独木舟最多...

NYOJ 贪心算法题目汇总(一)

题目6 题目信息 运行结果 本题排行 讨论区 喷水装置(一) 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述现有一块草坪,长为20米,宽为2米,要在横...

nyoj47过河问题(贪心)

过河问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,...

nyoj586 poj2456二分+贪心

二分查找贪心

POJ 3111 K Best &&NYOJ 914 (二分+ 贪心,最大化平均值)

poj3111 && NYOJ 914 有n个物品的重量和价值分别是w[i]和v[i],从中选出K个物品使得单位重量的价值最大。(1...

nyoj 题目 BUYING FEED 贪心算法

BUYING FEED 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 Farmer John needs to travel to town to pick...
  • BBHHTT
  • BBHHTT
  • 2017年08月01日 16:26
  • 92
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:nyoj-307 宝物【dp+贪心】
举报原因:
原因补充:

(最多只允许输入30个字)