【搜索】丛林探险

描述 Description 
 东非大裂谷中有一片神秘的丛林,是全世界探险家的乐园,著名黄皮肤探险家BB一直想去试试。正好我国科学家2005年4月将首次对东非大裂谷进行科考,BB决定随科考队去神秘丛林探险。在出发之前,他搜集了国内外有关神秘丛林探险的资料,并绘制成一张地图:该地图上有若干安全点(包括入口点和出口点),并将这些安全点编号为1、2、…、n;如果一个安全点和另一个安全点有一条路直接相通,则用一条边标示;该图是一个连通图(任意两点间有至少一条路径),地图上每条路的长度和走这条路需要耗费的体力都做了标示。
KK行走速度为1,并知道自己体力为K。他想知道根据自己的体力情况能否成功地穿过丛林。
   
   
 输入格式 Input Format 
 第一行两个整数n(<=5000)  m(<=40000),分别表示地图上安全点的个数和边的数目;
第2行至第m+1 行每行4个整数x  y  c d,x、y表示有直接相联边的两个点的编号,c走这条路需要耗费的体力;d表示边的长度;(其中150<=c,d<=300)
第m+2行两个整数s  t,分别表示安全的入口点和出口点的编号;
第m+3行一个整数k,表示BB的体力值;(K<10^9)
同一行上的多个数据用空格隔开。
   
   
  输出格式 Output Format 
 一个整数,如果BB能安全地从如入口穿过丛林到达出口,输出最短时间,否则输出-1
   
   
  样例输入 Sample Input 
 
   
   
  样例输出 Sample Output 
 
   
   
  时间限制 Time Limitation 
 各个测试点1s


有人用最短路做出来了,应该是数据弱了的原因。他们的方法是比较的时候先比较长度,再比较体力,实际上有反例。

因为一开始体力没超过限制的时候,就会尽量先满足长度最短而使体力变大,可能导致最后体力超过限制。实际上一开始为了保证能到达,不一定选择路径最短。


搜索是可以的,加个最优化剪枝就能过。


#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
using std::sort;

long s,t,k;
long ans = 0x3f3f3f3f;
long long dist[5010];
bool used[5010];
long que[2000010];
const long qmod = 2000000;
/*struct node
{
	long ind;
	long strenth;
	long length;
	node* nxt;
};
node* head[5010];
*/

struct Edge
{
	long u;
	long v;
	long strenth;
	long length;
	bool operator<(const Edge& e2)const
	{
		return u < e2.u;
	}
};

Edge edge[80010];
long start[5010];
long getint()
{
	long rs=0;bool sgn=1;char tmp;
	do tmp = getchar();
	while (!isdigit(tmp)&&tmp-'-');
	if (tmp == '-'){tmp=getchar();sgn=0;}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;	
}

void spfa1()
{
	memset(dist,0x3f,sizeof dist);
	dist[s] = 0;
	long l = 0;
	long r = 0;
	que[++r] = s;
	long u ,v;
	while (l < r)
	{
		l ++;
		if (l == qmod)
			l = 0;
		u = que[l];
		used[u] = false;
		for (long vv=start[u];edge[vv].u==u;vv++)
		{
			v = edge[vv].v;
			if (dist[v]>dist[u]+edge[vv].strenth)
			{
				dist[v] = dist[u] + edge[vv].strenth;
				if (!used[v])
				{
					used[v] = true;
					r ++;
					if (r == qmod)
						r = 0;
					que[r] = v;
				}
			}
		}
	}
}

void dfs(long u,long ss,long sl)
{
	if (sl >= ans)
	{
		return;
	}
	if (u == t)
	{
		if (ans > sl)
			ans = sl;
		return;
	}
	for (long vv=start[u];edge[vv].u==u;vv++)
	{
		long v = edge[vv].v;
		if (!used[v] && ss+edge[vv].strenth<=k)
		{
			used[v] = true;
			dfs(v,ss+edge[vv].strenth,sl+edge[vv].length);
			used[v] = false;
		}
	}
}
/*
void insert(long a,long b,long c,long d)
{
	node* nn = new node;
	nn -> ind = b;
	nn -> nxt = head[a];
	nn -> strenth = c;
	nn -> length = d;
	head[a] = nn;

	nn = new node;
	nn -> ind = a;
	nn -> nxt = head[b];
	nn -> strenth = c;
	nn -> length = d;
	head[b] = nn;
}
*/
int main()
{
	freopen("forest.in","r",stdin);
	freopen("forest.out","w",stdout);

	long n = getint();
	long m = getint();

	for (long i=0;i<m;i++)
	{
		edge[i*2+1].u = edge[i*2+2].v = getint();
		edge[i*2+1].v = edge[i*2+2].u = getint();
		edge[i*2+1].strenth = edge[i*2+2].strenth = getint();
		edge[i*2+1].length = edge[i*2+2].length = getint();
	}

	m <<= 1;
	sort(edge+1,edge+m+1);

	for (long i=1;i<m+1;i++)
	{
		if (!start[edge[i].u])
		{
			start[edge[i].u] = i;
		}
	}

	s = getint();
	t = getint();
	k = getint();

	spfa1();
	if (dist[t] > k)
	{
		printf("-1");
		return 0;
	}
	used[s] = true;
	dfs(s,0,0);
	printf("%ld",ans);
	return 0;
}


二分版本

#include <cstdio>
#include <string>
#include <cstring>

long s,t,k;
long n;
long mid;
bool used[5010];

struct node
{
	long ind;
	node* nxt;
	long c;
	long d;
};
node* head[5010];

long getint()
{
	long rs=0;bool sgn=1;char tmp;
	do tmp=getchar();
	while (!isdigit(tmp)&&tmp-'-');
	if (tmp=='-'){tmp=getchar();sgn=0;}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;
}

void insert(long a,long b,long c,long d)
{
	node* nn = new node;
	nn -> ind = b;
	nn -> nxt = head[a];
	nn -> c = c;
	nn -> d = d;
	head[a] = nn;
}

bool can(long u,long e,long s)
{
	if (s > mid)
		return false;
	if (u == t)
	{
		if (mid > s)
			mid = s;
		return true;
	}
	for (node* vv=head[u];vv;vv=vv->nxt)
	{
		long v = vv->ind;
		if (!used[v])
		{
			if (e-vv->c >= 0)
			{
				used[v] = true;
				if (can(v,e-vv->c,s+vv->d))
					return true;
				used[v] = false;
			}
		}
	}
	return false;
}

int main()
{
	freopen("forest.in","r",stdin);
	freopen("forest.out","w",stdout);

	n = getint();
	long m = getint();
	long sumd = 0;

	for (long i=1;i<m+1;i++)
	{
		long x = getint();
		long y = getint();
		long c = getint();
		long d = getint();
		insert(x,y,c,d);
		insert(y,x,c,d);
		sumd += d;
	}
	s = getint();
	t = getint();
	k = getint();

	long ans = 0x3f3f3f3f;
	long l = 0;
	long r = sumd;
	while (l <= r)
	{
		mid = (l+r)>>1;
		memset(used,0,sizeof used);
		used[s] = true;
		if (can(s,k,0))
		{
			if (ans > mid)
				ans = mid;
			r = mid-1;
		}
		else
		{
			l = mid+1;
		}

	}
	if (ans == 0x3f3f3f3f)
		printf("-1");
	else
		printf("%ld",ans);
	return 0 ;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值