埃雷萨拉斯寻宝【最短路】

题目大意:

题目链接:http://10.156.31.134/contestnew.aspx?cid=123 (学校局域网)

从第一行任一格子出发,到最后一行任一格子,可以传送到相同的魔法格里,经过不同的魔法格会损伤不同的生命(如果之前经过过就不会)。求最大剩余生命。


思路:

显然最短路啊。

因为同一个魔法格内可以互相传送,所以就按照魔法格的点权建点。
把每一个点拆成入点和出点,之间连长度为这个点损耗的生命值的边。
接下来,如果点xxyy有相邻,那么在这两个点分别相连。
然后跑一边dijdij就可以了。


代码:

#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#define mp make_pair
using namespace std;

const int N=2510;
int n,m,hp,ans,tot,head[N+N],dis[N+N],map[N][N];
bool used[N][N],vis[N+N];

struct edge
{
	int dis,next,to;
}e[N*N*4+N];

int read()
{
	int d=0;
	char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch))
		d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

void add(int from,int to,int dis)
{
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].next=head[from];
	head[from]=tot;
}

void dij()
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	priority_queue<pair<int,int> > q;
	for (int i=1;i<=n;i++)
    	if (!vis[map[1][i]])
    	{
    		vis[map[1][i]]=1;
    		q.push(mp(0,map[1][i]));
    		dis[map[1][i]]=0;
    	}
    memset(vis,0,sizeof(vis));
    while (q.size())
    {
        int u=q.top().second,v;
        q.pop();
        if (vis[u]) continue;
        vis[u]=1;
        for (int i=head[u];~i;i=e[i].next)
        {
            v=e[i].to;
            if (dis[v]>dis[u]+e[i].dis)
            {
                dis[v]=dis[u]+e[i].dis;
                q.push(mp(-dis[v],v));
            }
        }
    }
}

int main()
{
	freopen("data.txt","r",stdin);
	memset(head,-1,sizeof(head));
	n=read(),m=read(),hp=read();
	for (int i=1;i<=m;i++)
		add(i,i+m,read());
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			map[i][j]=read();
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
		{
			if (i>1&&!used[map[i][j]][map[i-1][j]])	add(map[i][j]+m,map[i-1][j],0),used[map[i][j]][map[i-1][j]]=1;
			if (i<n&&!used[map[i][j]][map[i+1][j]])	add(map[i][j]+m,map[i+1][j],0),used[map[i][j]][map[i+1][j]]=1;
			if (j>1&&!used[map[i][j]][map[i][j-1]])	add(map[i][j]+m,map[i][j-1],0),used[map[i][j]][map[i][j-1]]=1;
			if (j<m&&!used[map[i][j]][map[i][j+1]])	add(map[i][j]+m,map[i][j+1],0),used[map[i][j]][map[i][j+1]]=1;
		}
	dij();
	ans=1e9;
	for (int i=1;i<=n;i++)
		if (dis[map[n][i]+m]<ans) ans=dis[map[n][i]+m];
	if (ans<hp) printf("%d",hp-ans);
		else printf("NO");
	return 0;
}
posted @ 2019-04-27 14:20  全OI最菜  阅读(97)  评论(0编辑  收藏  举报