题目链接:http://code.bupt.edu.cn/problem/p/454/
454. 帮帮小叮当
题目描述
小叮当刚刚学会了传送门的使用方法,可是它不小心跌落到二维空间一个 n * m 的矩阵格子世界的入口(1,1)处,
他得知出口在(n,m)处,每穿越一个格子门,它的体力值会下降。
又饿又累的他 IQ 已经降为负数了,聪明的你,能帮他规划一下路线,使得它体力值下降的最少吗?
每一行有且仅有一个传送门,但是小叮当上课睡着了,只学会了用传送门瞬移到相邻行的另一个传送门且耗 1 滴体力。
此外,他就只能通过格子门走到相邻四个格子中的一个,也耗 1 滴体力。
ps,由于符合的路径太多了,你只需要告诉我们体力值消耗最小值。
输入格式
每组数据,第一行给 n,m 两个整数(2 <= n,m <= 10000),接下来一行,有 n 个数字,代表该行传送门的位置 x( 1 <= x <= m )。以 n,m 都为0结束。Mays温馨提醒:数据组数略大于100。
输出格式
对每组输入,输出一行,体力消耗最小值。
输入样例
5 5
5 4 3 2 1
0 0
输出样例
8
刚开始看这道题,不知道怎么解,后来听大牛们说,此题可以抽象成如下图:
五角星代表传送阵,圆圈代表起点和终点。由于要求最小的距离,那么,除了样例给出的极端情况以外,走传送门一定是可以节省体力的,那么,以起点到各传送门,传送门到传送门,传送门到终点建边,而边的权值为两点间的曼哈顿距离,传送门之间的边的权值都为1,。之后求出最短路径即可。
之前图论基础几乎为0....这次第一次用SPFA,解出来还是挺开心的^_^
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#define N 400100
using namespace std;
struct edge
{
int from,to,c,nxt;
}e[N];
int head[N];
int d[N];
int s;
bool vis[N];
int n,m;
int dist(int x,int y,bool S)
{
if(S)
return abs(x-1)+abs(y-1);
else
return abs(x-n)+abs(y-m);
}
void spfa(int s)
{
queue<int> q;
memset(d,0x3f,sizeof(d));
d[s]=0;
memset(vis,0,sizeof(vis));
q.push(s);
vis[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for(int k=head[x];k!=-1;k=e[k].nxt)
{
if(d[e[k].to]>d[e[k].from]+e[k].c)
{
d[e[k].to]=d[e[k].from]+e[k].c;
if(!vis[e[k].to])
{
vis[e[k].to]=1;
q.push(e[k].to);
}
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)&&(n||m))
{
memset(head,-1,sizeof(head));
int t=1,last;
for(int i=0;i<4*n-2;)
{
int temp;
scanf("%d",&temp);
e[i].from=0;
e[i].to=t;
e[i].c=dist(t,temp,1);
e[i].nxt=head[0];
head[0]=i++;
e[i].from=t;
e[i].to=n+1;
e[i].c=dist(t,temp,0);
e[i].nxt=head[t];
head[t]=i++;
if(i!=2)
{
e[i].from=t;
e[i].to=t-1;
e[i].c=1;
e[i].nxt=head[t];
head[t]=i++;
e[i].from=t-1;
e[i].to=t;
e[i].c=1;
e[i].nxt=head[t-1];
head[t-1]=i++;
}
t++;
}
spfa(0);
printf("%d\n",d[n+1]);
}
return 0;
}
下面是dijkstra的代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#define N 400100
using namespace std;
struct dij
{
int id,dist;
bool operator < (const dij s1) const
{
return dist>s1.dist;
}
};
struct edge
{
int from,to,c,nxt;
}e[N];
priority_queue<dij> q;
int head[N];
int d[N];
int s;
bool vis[N];
int n,m;
void dijkstra()
{
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
for(int i=0;i<n+2;i++) d[i]=99999999;
d[0]=0;
dij ss,tt;
ss.id=0;
ss.dist=0;
vis[ss.id]=true;
q.push(ss);
while(!q.empty())
{
tt=q.top();
q.pop();
int id=tt.id,dist=tt.dist;
vis[id]=true;
for(int k=head[id];k!=-1;k=e[k].nxt)
{
if(!vis[e[k].to] && d[e[k].to]>d[id]+e[k].c)
{
d[e[k].to]=d[id]+e[k].c;
ss.id=e[k].to;
ss.dist=d[e[k].to];
q.push(ss);
}
}
}
}
int dist(int x,int y,bool S)
{
if(S)
return abs(x-1)+abs(y-1);
else
return abs(x-n)+abs(y-m);
}
//void spfa(int s)
//{
// queue<int> q;
// memset(d,0x3f,sizeof(d));
// d[s]=0;
// memset(vis,0,sizeof(vis));
//
// q.push(s);
// vis[s]=1;
// while(!q.empty())
// {
// int x=q.front();
// q.pop();
// vis[x]=0;
// for(int k=head[x];k!=-1;k=e[k].nxt)
// {
// if(d[e[k].to]>d[e[k].from]+e[k].c)
// {
// d[e[k].to]=d[e[k].from]+e[k].c;
// if(!vis[e[k].to])
// {
// vis[e[k].to]=1;
// q.push(e[k].to);
// }
// }
// }
// }
//
//}
int main()
{
while(~scanf("%d%d",&n,&m)&&(n||m))
{
memset(head,-1,sizeof(head));
int t=1,last;
for(int i=0;i<4*n-2;)
{
int temp;
scanf("%d",&temp);
e[i].from=0;
e[i].to=t;
e[i].c=dist(t,temp,1);
e[i].nxt=head[0];
head[0]=i++;
e[i].from=t;
e[i].to=n+1;
e[i].c=dist(t,temp,0);
e[i].nxt=head[t];
head[t]=i++;
if(i!=2)
{
e[i].from=t;
e[i].to=t-1;
e[i].c=1;
e[i].nxt=head[t];
head[t]=i++;
e[i].from=t-1;
e[i].to=t;
e[i].c=1;
e[i].nxt=head[t-1];
head[t-1]=i++;
}
t++;
}
dijkstra();
printf("%d\n",d[n+1]);
}
return 0;
}