SOJ 4243: Saving Girl
2012-12-09 14:30
363 查看
挺好玩的一道最短路的题,
当初学算法的时候最先学的就是最短路,
但这么长时间都只是用SPFA解决裸的最短路问题,一直不知道它有什么别的应用。。
所以碰到这道题的时候觉得很有意思,就把题解放上来
题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=4243
题目大意:给你一张n*m的地图,地图上的某些格子摆放着武器,每种武器有自己的伤害值和伤害范围,有武器的格子是不可达的,问你从左上角走到右下角所损失的最小的生命值是多少。
算法:
首先预处理,把走到每个格子时需损耗生命值算出来,作为这个格子的权值。
问题转换为,从(1,1)到(n,m)寻找一条由可达点组成的路径,使路径上的权值和最小。
建图:如果格子u和格子v均可达,且格子v的权值为w,则建立一条边(u,v),权值为w。
然后对(1,1)到(n,m)用SPFA寻找最短路。
图还是有点儿大的,所以肯定没必要用临接表存边,
因为每个点只可能跟它上下左右的点之间存在边,所以对每个出队的点只要判断它上下左右的点是否可达就行了。
Trick:考虑从起点到终点根本就不存在合法路径的情况
第一次写题解,生怕别人看不懂= =
一道水题啰啰嗦嗦这么一堆。。。
再一次发现我的代码风格真的是没法看啊没法看。。。
sigh......
当初学算法的时候最先学的就是最短路,
但这么长时间都只是用SPFA解决裸的最短路问题,一直不知道它有什么别的应用。。
所以碰到这道题的时候觉得很有意思,就把题解放上来
题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=4243
题目大意:给你一张n*m的地图,地图上的某些格子摆放着武器,每种武器有自己的伤害值和伤害范围,有武器的格子是不可达的,问你从左上角走到右下角所损失的最小的生命值是多少。
算法:
首先预处理,把走到每个格子时需损耗生命值算出来,作为这个格子的权值。
问题转换为,从(1,1)到(n,m)寻找一条由可达点组成的路径,使路径上的权值和最小。
建图:如果格子u和格子v均可达,且格子v的权值为w,则建立一条边(u,v),权值为w。
然后对(1,1)到(n,m)用SPFA寻找最短路。
图还是有点儿大的,所以肯定没必要用临接表存边,
因为每个点只可能跟它上下左右的点之间存在边,所以对每个出队的点只要判断它上下左右的点是否可达就行了。
Trick:考虑从起点到终点根本就不存在合法路径的情况
#include<cstdio> #include<cstring> #include<deque> using namespace std; char s[105][105]; int a[105][105],n,m,d[105][105]; int main() { int i,j,k,q,h; while(scanf("%d%d",&n,&m)==2) { getchar(); memset(a,0,sizeof(a)); memset(d,-1,sizeof(d)); for(i=0;i<n;i++)gets(s[i]); if(s[n-1][n-1]!='.'||s[0][0]!='.'){printf("Die..\n");continue;} for(i=0;i<n;i++) for(j=0;j<n;j++) { if(s[i][j]=='.')continue; if(s[i][j]=='G')k=1; else if(s[i][j]=='M')k=2; else k=3; h=2*k-1; for(q=j-1;q>=j-k;q--) { if(q<0)break; a[i][q]+=h; } for(q=j+1;q<=j+k;q++) { if(q>=n)break; a[i][q]+=h; } for(q=i-1;q>=i-k;q--) { if(q<0)break; a[q][j]+=h; } for(q=i+1;q<=i+k;q++) { if(q>=n)break; a[q][j]+=h; } } deque<int>dd; dd.push_back(0); d[0][0]=a[0][0]; while(!dd.empty()) { i=dd.front(); dd.pop_front(); j=i%n; i/=n; if(i>0&&s[i-1][j]=='.') { k=(i-1)*n+j; if(d[i-1][j]==-1||d[i-1][j]>d[i][j]+a[i-1][j]){d[i-1][j]=d[i][j]+a[i-1][j];dd.push_back(k);} } if(i<n-1&&s[i+1][j]=='.') { k=(i+1)*n+j; if(d[i+1][j]==-1||d[i+1][j]>d[i][j]+a[i+1][j]){d[i+1][j]=d[i][j]+a[i+1][j];dd.push_back(k);} } if(j>0&&s[i][j-1]=='.') { k=i*n+j-1; if(d[i][j-1]==-1||d[i][j-1]>d[i][j]+a[i][j-1]){d[i][j-1]=d[i][j]+a[i][j-1];dd.push_back(k);} } if(j<n-1&&s[i][j+1]=='.') { k=i*n+j+1; if(d[i][j+1]==-1||d[i][j+1]>d[i][j]+a[i][j+1]){d[i][j+1]=d[i][j]+a[i][j+1];dd.push_back(k);} } } if(d[n-1][n-1]!=-1&&d[n-1][n-1]<m)printf("Girl~\n"); else printf("Die..\n"); } }
第一次写题解,生怕别人看不懂= =
一道水题啰啰嗦嗦这么一堆。。。
再一次发现我的代码风格真的是没法看啊没法看。。。
sigh......
相关文章推荐
- soj 4243 最短路 spfa实现
- SOJ 3427 Dark roads
- soj 3109: Space flight 最大权闭合图
- soj 1001. Alphacode
- soj 2832 强连通分量
- SOJ 3085: windy's cake V
- soj 1777. Mix order traversal
- soj 1801. Reading books
- 【soj 2370】Just The Simple Fax( http://soj.me/show_problem.php?pid=2370)
- SOJ 2775: Breaking Strings
- Sicily 1135 飞越原野 (SOJ 1135) 【BFS 广度优先搜索】
- SOJ 1091: 指环王
- SOJ 1052. Candy Sharing Game
- SOJ-Dollars
- SOJ - 1002 POJ - 2034 Anti-prime Sequences
- SOJ 1424 奖金
- soj 12647. Sightseeing
- soj1093伊拉克
- soj 2818 dp
- HDU 4243 排列循环节问题-思维-(排列组合)