5 1 5 3 3 1 2 5 0
3http://acm.hdu.edu.cn/showproblem.php?pid=1548
可以用到的算法:Dijkstra、BFS、DP
题意:
有一个特别的电梯,第i层有一个对应的数字ki, 对于第i层按上升键up可升上到i+k[i]层,按下降键down到达i-k[i]层,到达的楼层最高不能超过n层,最低不能小于1层。给你一个起点A和终点B,问最少要按几次上升键或者下降键到达目的地。
思路一:
最短路:把每一层都看成一个节点,问题就可以变成求起点到终点的最短路径问题。
用Dijkstra算法和BFS算法都可以解。Dijkstra: 100+MS
#include<iostream> using namespace std; #define INF 999999 int map[500][500]; int dist[500],used[500]; int n; void Dijkstra(int v) { int i,j,pos,min; memset(used,0,sizeof(used)); for(i=1;i<=n;i++) dist[i]=map[v][i]; used[v]=1; dist[v]=0;//floor A==floor B(起点就是终点)的情况 for(j=1;j<n;j++) { pos=0; min=100000000; for(i=1;i<=n;i++) if(dist[i]<min&&used[i]==0) { pos=i; min=dist[i]; } used[pos]=1; for(i=1;i<=n;i++) if(dist[i]>dist[pos]+map[pos][i]) dist[i]=dist[pos]+map[pos][i]; } } int main() { int s,t,i,j; int a[500]; while(cin>>n,n) { cin>>s>>t; memset(map,INF,sizeof(map)); for(i=1;i<=n;i++) { cin>>a[i]; if(i+a[i]<=n) map[i][i+a[i]]=1;//构图必须是单向边 if(i-a[i]>=1) map[i][i-a[i]]=1; } Dijkstra(s); if(dist[t]>INF)//If you can't reach floor B,printf "-1" cout<<-1<<endl; else cout<<dist[t]<<endl; } return 0; }
BFS:15MS#include<cstdio> #include<queue> #include<cstring> using namespace std; #define maxn 250 bool visit[maxn]; int floor[maxn][2];//floor[i][0]表示第i层向上能到的楼层,floor[i][1]则表示向下能到的楼层 int n,start,end; struct node { int pos,t; }temp,p; queue<node> q; int BFS() { memset(visit,false,sizeof(visit)); while(!q.empty()) { temp=q.front(); q.pop(); visit[temp.pos]=true; if(temp.pos==end) return temp.t; int up=floor[temp.pos][0],down=floor[temp.pos][1]; if(up!=-1&&!visit[up]) { p.pos=up; p.t=temp.t+1; q.push(p); } if(down!=-1&&!visit[down]) { p.pos=down; p.t=temp.t+1; q.push(p); } } return -1; } int main() { while(scanf("%d",&n),n) { scanf("%d %d",&start,&end); memset(floor,-1,sizeof(floor)); while(!q.empty()) q.pop(); for(int i=1;i<=n;i++) { int t; scanf("%d",&t); temp.pos=i; floor[i][0]=floor[i][1]=-1; if(i+t<=n) floor[i][0]=i+t; if(i-t>=1) floor[i][1]=i-t; if(i==start) { temp.t=0; q.push(temp); } } temp=q.front(); printf("%d\n",BFS()); } return 0; }
思路二:
DP: dp[i]表示从起点到第i层的按按钮的最少次数 31MS
DP:#include<cstdio> #include<cstring> #define maxn 250 #define INF 0x3f3f3f3f int dp[maxn],floor[maxn][2];//floor[i][0]表示第i层向上能到的楼层,floor[i][1]则表示向下能到的楼层 int main(){ int n,a,b; while(scanf("%d",&n),n){ scanf("%d %d",&a,&b); memset(floor,-1,sizeof(floor)); for(int i=1;i<=n;i++){ int t; scanf("%d",&t); if(i+t<=n) floor[i][0]=i+t; if(i-t>=1) floor[i][1]=i-t; } memset(dp,0x3f,sizeof(dp)); dp[a]=0; while(true){ int num=0;//记录更新数据的次数 for(int i=1;i<=n;i++){ if(dp[i]<INF){ for(int j=0;j<2;j++){ if(floor[i][j]!=-1){ if(dp[floor[i][j]]>dp[i]+1) dp[floor[i][j]]=dp[i]+1,num++; } } } } if(num==0)//无法继续更新 break; } if(dp[b]==INF) dp[b]=-1; printf("%d\n",dp[b]); } return 0; }