HD201404最短路径

【试题描述】

a、b、c是3个互不相等的1位正数,用它们和数字0可以填满一个n行n列的方格阵列,每格中都有4种数码中的一个。填入0的格子表示障碍物,不能属于任何路径。你是否能找出一条从1行1列出发,到达n行n列且代价最小的路径呢?注意:每一格只能走向与之相邻的上、下、左、右的非0且不出界的格子。而所谓路径代价指的是路径经过的所有格子中的数字总和。请你编程求出从1行1列的位置出发到达n行n列的最小路径代价,若无法到达就输出-1。

【输入要求】

第一行输入数字n。
接下来的n行每行是一个长度为n的数字串,这n个字符串就构成了一个数字符的方阵。方阵中除了'0'外,最多还可以包含3种数字符。

【输出要求】

仅有最小代价或-1这一个整数。

【输入实例】

【输入样例1】
4
1231
2003
1002
1113
【输入样例2】
4
3150
1153
3311
0530

【输出实例】

【输出样例1】
10
【输出样例2】
-1

【其他说明】

60%的数据,n<10,80%的数据,n<100,100%的数据,n<1000

【试题分析】

第一眼:这不就是迷宫吗!?看我秒过!!

第二眼:还不太一样,迷宫是走一步ans++,这个是要加一个变量的

第三眼:上DFS代码吧!!

于是就花了1小时yy了这么一个代码:

#include<iostream>
#include<cstring>
using namespace std;
char map[1001][1001],cinm[1001][1001];
int a[1001][1001],ans=0,m,n,k[1001][1001],k1[1001][1001],mk=0;//k不变,变的只是k1.
void res(int u,int v,int i,int j)
{
int t=k1[u][v];
if(u==i&&v==j) ans=t,mk=1;
if(v<m-1&&map[u][v+1]!='#'&&a[u][v+1]>t+k[u][v+1])
{
k1[u][v+1]=k[u][v+1]+t;
a[u][v+1]=k1[u][v+1];
res(u,v+1,i,j);
}
if(u>0&&map[u-1][v]!='#'&&a[u-1][v]>t+k[u-1][v])
{
k1[u-1][v]=k[u-1][v]+t;
a[u-1][v]=k1[u-1][v];
res(u-1,v,i,j);
}
if(v>0&&map[u][v-1]!='#'&&a[u][v-1]>t+k[u][v-1])
{
k1[u][v-1]=k[u][v-1]+t;
a[u][v-1]=k1[u][v-1];
res(u,v-1,i,j);
}
if(u<n-1&&map[u+1][v]!='#'&&a[u+1][v]>t+k[u+1][v])
{
k1[u+1][v]=k[u+1][v]+t;
a[u+1][v]=k1[u+1][v];
res(u+1,v,i,j);
}
}
int main()
{
cin>>n;
m=n;
for(int i=0;i<n;i++)
{
cin>>cinm[i];
for(int j=0;j<n;j++)
{
k[i][j]=cinm[i][j]-'0';
k1[i][j]=k[i][j];
}
}
int startx=0,starty=0,endx=n-1,endy=n-1;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(i==startx&&j==starty) map[i][j]='S';
else if(i==endx&&j==endy) map[i][j]='T';
if(k[i][j]==0)map[i][j]='#';
else map[i][j]='.';
}
memset(a,1,sizeof(a));
a[0][0]=0;
res(startx,starty,endx,endy);
if(mk==1)cout<<ans<<endl;
else cout<<-1;
}

结果没有看数据范围,1000!!?

结果对了,但是就是时间超了。

细细想来也没有神马办法优化,罢罢罢……

BFS:

好了,如果DFS时间超限,那么只能用BFS了。

于是又yy了一个BFS的代码:

#include<iostream>
using namespace std;
char Graph[1001][1001];
int n,m,startx,starty;
int Dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int Vis[1001][1001];
int Dis[1001][1001];
char cinm[1001][1001],k[1001][1001];
int Fit(int x,int y)
{
return (x>=1&&x<=n&&y>=1&&y<=m);
}
int BFS(int x,int y)
{
int queue[100000];
int i,head=0,tail=0;
queue[tail++]=x;
queue[tail++]=y;
Vis[x][y]=1;
while(head<tail)
{
int nowx=queue[head++];
int nowy=queue[head++];
for(i=0;i<4;i++)
{
int tmpx=nowx+Dir[i][0];
int tmpy=nowy+Dir[i][1];
if(Fit(tmpx,tmpy)&&tmpx==n&&tmpy==n&&Graph[tmpx][tmpy]=='.') return Dis[nowx][nowy]+k[tmpx][tmpy];
if(Fit(tmpx,tmpy)&&Graph[tmpx][tmpy]=='.'&&Dis[nowx][nowy]+k[tmpx][tmpy]<Dis[tmpx][tmpy])
{
Dis[tmpx][tmpy]=Dis[nowx][nowy]+k[tmpx][tmpy];
queue[tail++]=tmpx;
queue[tail++]=tmpy;
}
}
}
return 0;
}
int main()
{
int i ,j ,startx=1,starty=1;
scanf("%d",&n);
m=n;
for(int i=1;i<=n;i++)
{
scanf("%s",cinm[i]+1);
for(int j=1;j<=n;j++)
k[i][j]=cinm[i][j]-'0',Dis[i][j]=999999;
}
Dis[1][1]=k[1][1];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(k[i][j]==0)Graph[i][j]='#';
else Graph[i][j]='.';
}
int ans=0;
ans=BFS(startx,starty);
if(ans!=0) printf("%d\n",ans);
else printf("-1\n");
}
/*
7
3221000
3110012
3123031
1123301
2211123
0012333
3312001*/

  结果错误。

有些点的确能A,但是有些点死活A不了。

突然发现了这样一个条件:最多有三个除0之外不同的数,于是又yy了一个三个队列维护的代码:

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
char cinm[1001][1001];
int n,Dis[1001][1001],Vis[1001][1001],number[1001],timek,k[1001][1001];
struct P
{
int x,y;
bool operator < (const P& ths) {return Dis[x][y]<Dis[ths.x][ths.y];}
};
queue<P> que[3];
int getfront()
{
int c=-1;
if(que[0].size()) c=0;
if(que[1].size()&&(c<0||que[1].front()<que[c].front())) c=1;
if(que[2].size()&&(c<0||que[2].front()<que[c].front())) c=2;
return c;
}
int Fit(int x,int y)
{
return (x>=1&&x<=n&&y>=1&&y<=n);
}
int Dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//方向数组
int BFS()
{
if(k[1][1]==0||k[n][n]==0) return -1;
que[number[cinm[1][1]]].push((P){1,1});
Dis[1][1]=k[1][1];
while(que[0].size()+que[1].size()+que[2].size())//当三个队列的大小和非空时
{
int t=getfront();
int x=que[t].front().x;
int y=que[t].front().y;//获取坐标
que[t].pop();
if(x==n&&y==n) return Dis[x][y];
if(Vis[x][y]==1) continue;
Vis[x][y]=1;
for(int i=0;i<=3;i++)
{
int nx=x+Dir[i][0];
int ny=y+Dir[i][1];
if(Fit(nx,ny)&&k[nx][ny]!=0&&Dis[x][y]+k[nx][ny]<Dis[nx][ny])
{
Dis[nx][ny]=Dis[x][y]+k[nx][ny];
que[number[cinm[nx][ny]]].push((P){nx,ny});
}
}
}
return -1;
}
int main()
{
n=read();
for(int i=1;i<=n;i++) scanf("%s",cinm[i]+1);
memset(number,-1,sizeof(number));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(number[cinm[i][j]]<0&&cinm[i][j]!='0') number[cinm[i][j]]=timek++;//为非0元素标号
Dis[i][j]=99999999;
k[i][j]=cinm[i][j]-'0';
}
printf("%d\n",BFS());
}

【代码】

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
char cinm[1001][1001];
int n,Dis[1001][1001],Vis[1001][1001],number[1001],timek,k[1001][1001];
struct P
{
int x,y;
bool operator < (const P& ths) {return Dis[x][y]<Dis[ths.x][ths.y];}
};
queue<P> que[3];
int getfront()
{
int c=-1;
if(que[0].size()) c=0;
if(que[1].size()&&(c<0||que[1].front()<que[c].front())) c=1;
if(que[2].size()&&(c<0||que[2].front()<que[c].front())) c=2;
return c;
}
int Fit(int x,int y)
{
return (x>=1&&x<=n&&y>=1&&y<=n);
}
int Dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//方向数组
int BFS()
{
if(k[1][1]==0||k[n][n]==0) return -1;
que[number[cinm[1][1]]].push((P){1,1});
Dis[1][1]=k[1][1];
while(que[0].size()+que[1].size()+que[2].size())//当三个队列的大小和非空时
{
int t=getfront();
int x=que[t].front().x;
int y=que[t].front().y;//获取坐标
que[t].pop();
if(x==n&&y==n) return Dis[x][y];
if(Vis[x][y]==1) continue;
Vis[x][y]=1;
for(int i=0;i<=3;i++)
{
int nx=x+Dir[i][0];
int ny=y+Dir[i][1];
if(Fit(nx,ny)&&k[nx][ny]!=0&&Dis[x][y]+k[nx][ny]<Dis[nx][ny])
{
Dis[nx][ny]=Dis[x][y]+k[nx][ny];
que[number[cinm[nx][ny]]].push((P){nx,ny});
}
}
}
return -1;
}
int main()
{
n=read();
for(int i=1;i<=n;i++) scanf("%s",cinm[i]+1);
memset(number,-1,sizeof(number));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(number[cinm[i][j]]<0&&cinm[i][j]!='0') number[cinm[i][j]]=timek++;//为非0元素标号
Dis[i][j]=99999999;
k[i][j]=cinm[i][j]-'0';
}
printf("%d\n",BFS());
}

【HDNOIP】HD201404最短路径的更多相关文章

  1. Johnson 全源最短路径算法

    解决单源最短路径问题(Single Source Shortest Paths Problem)的算法包括: Dijkstra 单源最短路径算法:时间复杂度为 O(E + VlogV),要求权值非负: ...

  2. Floyd-Warshall 全源最短路径算法

    Floyd-Warshall 算法采用动态规划方案来解决在一个有向图 G = (V, E) 上每对顶点间的最短路径问题,即全源最短路径问题(All-Pairs Shortest Paths Probl ...

  3. Dijkstra 单源最短路径算法

    Dijkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家 Edsger Dijkstra 于 1956 年 ...

  4. Bellman-Ford 单源最短路径算法

    Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 Richard Bellman 和 Leste ...

  5. 最短路径算法-Dijkstra

    Dijkstra是解决单源最短路径的一般方法,属于一种贪婪算法. 所谓单源最短路径是指在一个赋权有向图中,从某一点出发,到另一点的最短路径. 以python代码为例,实现Dijkstra算法 1.数据 ...

  6. bzoj 4016: [FJOI2014]最短路径树问题

    bzoj4016 最短路路径问题 Time Limit: 5 Sec Memory Limit: 512 MB Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点 ...

  7. 51nod 1459 迷宫游戏 (最短路径—Dijkstra算法)

    题目链接 中文题,迪杰斯特拉最短路径算法模板题. #include<stdio.h> #include<string.h> #define INF 0x3f3f3f3f ],v ...

  8. C++迪杰斯特拉算法求最短路径

    一:算法历史 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是以 ...

  9. 求两点之间最短路径-Dijkstra算法

     Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.D ...

随机推荐

  1. magento去掉add to cmpre和email to friend

    修改:\app\design\frontend\default\blanco\template\catalog\product下list.phtml 和app\design\frontend\defa ...

  2. SQL Server 视图修改后有错怎么办?

    sp_refreshview 视图名:刷新指定视图 spsqlrefreshallviews:刷新全部视图

  3. sell-- Calendar 和 Date- 01,月份不变年份+3或直接到2017

    1. 2016/11/24 import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calen ...

  4. 在CentOS6.5上安装Tomcat6

    Tomcat安装一向方便,linux的比win的更是这样,基本就是拷贝,类似于win中备受青睐的绿色软件,下面只是记录一下过程. 1.从 http://mirrors.cnnic.cn/apache/ ...

  5. sqlserver多表连接更新

    一.MS SQL Server 多表关联更新 sql server提供了update的from 子句,可以将要更新的表与其它的数据源连接起来.虽然只能对一个表进行更新,但是通过将要更新的表与其它的数据 ...

  6. How to delete expired archive log files using rman?

    he following commands will helpful to delete the expired archive log files using Oracle Recovery Man ...

  7. 脚本编程中的test、bash调试、变量计算、参数

    脚本编程中的test.bash调试.变量计算.参数 1.文件测试 -e FILE:测试文件是否存在 -f FILE:测试文件是否为普通文件 -d FILE:测试路径是否为目录 -r FILE:测试当前 ...

  8. Hadoop学习笔记: HDFS

    注:该文内容部分来源于ChinaHadoop.cn上的hadoop视频教程. 一. HDFS概述 HDFS即Hadoop Distributed File System, 源于Google发表于200 ...

  9. 解决Regsvr32: DllRegisterServer entry point was not found

    原因: 虽然项目里面包含了DEF文件, 但是尼玛没有配置项目属性让链接器处理它啊! 解决方案: 项目属性->链接器->输入->模块定义文件->{输入文件名}

  10. 修改了系统自带头文件后,Xcode会报错

    1.Xcode自带头文件的路径 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Develo ...