【基础练习】【最短路堆优dij】tyvj1376 魔域之战题解

P1376 魔域之战
时间: 1000ms / 空间: 131072KiB / Java类名: Main

描述

    小A成功地在紧要关头逃离了神奇山洞,同时他也感觉自己rp大增。现在他站在了一座阴森森的城堡前,这就是江湖人称“死亡城堡”的魔域。为了rp,小A毅然决然地走了进去……
    不愧是死亡城堡,险境丛生,小A又是一个大意的人,XXX他掉进了一个陷阱。
    这是一个n*n的矩阵陷阱,矩阵的每一个小格内都有一个魔鬼,并且这些魔鬼属于不同的种类,种类数不超过p(1<=p<=n*n,有可能存在某一种魔鬼不在矩阵中出现)。每一种魔鬼i都有一种战斗力c[i],不同的魔鬼战斗力不同。打魔鬼也不是那么好玩的,需要消耗小A相应数量的战斗力。当小A打败了一个魔鬼后,此种类型的魔鬼就会全部消失,这样小A就可以自由的在这种类型的格子间传送,不会消耗任何的战斗力。每到一个格子,小A可以向紧邻的上下左右四个格子进发去打魔鬼,直到走出矩阵。小A开始郁闷了,他怎样才能从矩阵的第一行出发,顺利的走到矩阵的最后一行呢?所谓的顺利,就是使自己的战斗力大于0。
    现在小A求助于聪明的你,希望你能求出小A顺利走出陷阱时剩余的最大战斗力。

输入格式

    第一行:两个整数n,p;
    第2到n+1行是一个n*n的矩阵,矩阵中不同的数字代表不同的格子类型;
    第n+2行是p个数,代表p种魔鬼的战斗力;
    最后一行:小A的初始战斗力值W。

输出格式

    一个整数表示小A顺利走出陷阱时剩余的最大战斗力,如果小A走不出陷阱就输出'Dangerous!';

测试样例1

输入

样例一: 
3 3 
1 2 1 
2 1 2 
1 1 1 
1 2 5 

样例二: 
3 3 
1 2 1 
2 1 2 
3 3 3 
1 2 5 
2

输出

样例一: 

样例二: 
Dangerous!

备注

对于30%的数据:1<=n<=50
对于100%的数据:1<=n<=500;w<=maxlongint
看到这个题目就想到图论,当时忍不住感叹这真是个奇怪的想法,然而还是写了···事实证明思路是正确的 这题目可以跑BFS或最短路都可 

BFS的思路,就是上下左右搜索,以点权为代价,搜到一个新的类型,就把相同元素全部入队,同时记录当前剩余体力,如果走到最后一行输出即可

而图论的思路,我想的略麻烦:建立一个原点,向第一排各点连边,边权为代价;每个点向右向下连双向边;相同类型的点连边权为0的双向边,跑堆优dij

这样子边太多了,大数据会爆空间。实际上更好的方法是把同一类型的点当做一个点,每次读入数据记录不同类型点之间的关系,原点连第一排有的点的种类,最后一排出现的种类连向终点,跑SPFA即可

我只写了麻烦版本的代码,然而竟然能过···顺带吐槽下我们信手改题的07级学长,泥萌现在大概大学毕业两年了吧···

//trap
//copyright by ametake
#include
#include
#include
#include
#include 
#include
using namespace std;

const int maxn=250000+10;
const int maxm=6001000+10;
const int oo=2147483647;

struct data
{
	int v,w,next;
}e[maxm];//edge 终点,边权,下一条同源边 

struct w
{
	int dist,num,k;
	bool operator < (w n2)const
	{
		return dist>n2.dist;
	}             
}node[maxn];//每个node是一个点,有编号和dist 

vector vec[maxn];

int ne,m,p;//矩阵大小m*m 边数带计算 
int head[maxn],cost[maxn],cnt[maxn];
bool vis[maxn];
int tot,ans;

void insert(int x,int y,int w)
{
	ne++;
	e[ne].v=y;
	e[ne].w=w;
	e[ne].next=head[x];
	head[x]=ne;
} 

void init()
{
	scanf("%d%d",&m,&p);//读入矩阵长度,鬼种类 
	memset(head,-1,sizeof(head));
	int x;
	for (int i=1;i<=m;i++)
	{
		for (int j=1;j<=m;j++)
		{
			scanf("%d",&x);
			node[(i-1)*m+j].k=x;
			cnt[x]++;
			vec[x].push_back((i-1)*m+j);
		}
	}
	for (int i=1;i<=p;i++) scanf("%d",&cost[i]);
	scanf("%d",&tot);
	return;
}

void makeit()
{
	for (int i=1;i<=m;i++) insert(0,i,cost[node[i].k]);
	for (int i=1;i<=p;i++)
	{
		if (cnt[i]>0)
		{
			for (int j=0;j q;
	node[k].dist=0;
	q.push(node[k]);
	int disj,minj;//dis of j and number of j
	while (!q.empty()) 
	{
		minj=q.top().num;
		disj=q.top().dist;
		vis[minj]=true;
		q.pop();
	    int pi=head[minj];
	    while (pi!=-1)
	    {
	    	if (!(vis[e[pi].v]) && (disj+e[pi].w < node[e[pi].v].dist || disj == oo))
	    	    {node[e[pi].v].dist=disj+e[pi].w;q.push(node[e[pi].v]);}
	    	pi=e[pi].next;
		}
	}
	//首先循环一边找出dist最小的点
	//然后循环一边对于每个点以dist为中间点更小就更新dist 
	//从当前dist连着的边里找 
}

int main()
{
	//freopen("1.txt","r",stdin);
	//freopen("2.txt","w",stdout);
	freopen("trap.in","r",stdin);
	freopen("trap.out","w",stdout);
	init();
	makeit();
	for (int i=1;i<=m*m;i++)
	{
		node[i].num=i;
		node[i].dist=oo;
	}
	node[0].num=0;
	dij(0);
	ans=oo;
	for (int i=m*m-m+1;i<=m*m;i++) if (node[i].dist=ans) printf("%d\n",tot-ans);
	else printf("Dangerous!\n");
	return 0;
}





	/*
	for (int i=1;i<=ne;i++) printf("%d %d %d\n",i,e[i].v,e[i].w);
	
	for (int i=1;i<=m;i++)
	{
		for (int j=1;j<=m;j++)
		{
			printf("%d ",node[(i-1)*m+j].k);
		}
		printf("\n");
	}
	for (int i=1;i<=m*m;i++) printf("%d %d\n",i,node[i].dist);
	*/
/*
void makeit()
{
	for (int i=1;i<=m;i++) insert(0,i,cost[node[i].k]*cnt[node[i].k]);
	for (int i=1;i<=p;i++)
	{
		if (cnt[i]>0)
		{
			for (int j=0;j

——忽然一夜清香发,散作乾坤万里春



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值