UVALive 4128 Steam Roller(最短路(拆点,多状态))
题意:模拟了汽车的行驶过程,边上的权值为全速通过所消耗的时间,而起步(从起点出发的边)、刹车(到终点结束的边)、减速(即将拐弯的边)、加速(刚完成拐弯的边)这四种不能达到全速的情况,消耗的时间为权值*2。问从起点到终点所消耗的最少时间。
这道题主要是建图,很复杂,无耻地照着书上的代码码了一遍。让状态搞糊涂了= =
注意:
1、grid[][][4]记录了点的上下左右四条边的权值,id[][][4][2]记录各个点。
2、到一个点的最短路可以是路过这个点再折返回来,e.g:1->2 c=17,2->3 c=4,从1->2的最短路为17+8+8=33<34
3、原图总点数上限100*100,而拆点后共有8*100*100个点,狠狠地RE了一发。
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std; const int MAXN=;
const int maxr=,maxc=;
const int INF =1e9; const int UP=,LEFT=,DOWN=,RIGHT=;
const int inv[]={,,,};
const int dr[]={-,,,};
const int dc[]={,-,,}; struct Edge{
int u,v,c;
}; struct HeapNode{
int c,u;
bool operator < (const HeapNode rhs)const {
return c>rhs.c;
}
}; struct Dijkstra{
int n,m;
vector<Edge>edges;
vector<int>G[MAXN];
bool vis[MAXN];
int d[MAXN],p[MAXN]; void init(int n)
{
this->n=n;
for(int i=;i<n;i++)
G[i].clear();
edges.clear();
} void add(int u,int v,int c)
{
edges.push_back((Edge){u,v,c});
m=edges.size();
G[u].push_back(m-);
} void dijkstra(int st)
{
priority_queue<HeapNode>q;
for(int i=;i<n;i++)
d[i]=INF;
d[st]=;
memset(vis,,sizeof(vis));
q.push((HeapNode){,st});
while(!q.empty())
{
HeapNode x=q.top();q.pop();
int u=x.u;
if(vis[u])
continue;
vis[u]=true;
int sz=G[u].size();
for(int i=;i<sz;i++)
{
Edge e=edges[G[u][i]];
if(d[e.v]>d[u]+e.c){
d[e.v]=d[u]+e.c;
q.push((HeapNode){d[e.v],e.v});
}
}
}
}
}; int grid[maxr][maxc][]; int n,id[maxr][maxc][][]; int ID(int r,int c,int dir,int doubled)
{
int& x=id[r][c][dir][doubled];
if(x==)x=++n;
return x;
} int R,C; bool cango(int r,int c,int dir)
{
if(r<||r>=R||c<||c>=C)
return false;
return grid[r][c][dir]>;
} Dijkstra solver; int readint()
{
int x;
scanf("%d",&x);
return x;
} int main()
{
int r1,c1,r2,c2,kase=;
while(scanf("%d%d%d%d%d%d",&R,&C,&r1,&c1,&r2,&c2)==&&R)
{
r1--;c1--;r2--;c2--;
memset(grid,,sizeof(grid));
for(int r=;r<R;r++)//每次更新点(r,c)的下方和右方的边
{
for(int c=;c<C-;c++)
grid[r][c][RIGHT]=grid[r][c+][LEFT]=readint();
if(r!=R-)
for(int c=;c<C;c++)
grid[r][c][DOWN]=grid[r+][c][UP]=readint();
} solver.init(R*C*+); n=;
memset(id,,sizeof(id)); for(int dir=;dir<;dir++)//对起点做double
if(cango(r1,c1,dir))
solver.add(,ID(r1+dr[dir],c1+dc[dir],dir,),grid[r1][c1][dir]*); for(int r=;r<R;r++)//要把所有点都处理完整,不能到r2,c2就结束
for(int c=;c<C;c++)
for(int dir=;dir<;dir++)
if(cango(r,c,inv[dir]))
//为什么是inv?grid[r][c][inv[dir]]是点(r,c)沿inv[dir]方向到点x的边权,同样也是点x->点(r,c)的边权:老边
//而区别在于判断进入(r,c)的边,与出(r,c)进(new,r,newc)的边方向是否一致
for(int newdir=;newdir<;newdir++)
if(cango(r,c,newdir))
for(int doubled=;doubled<;doubled++){
int newr=r+dr[newdir];
int newc=c+dc[newdir];
int v=grid[r][c][newdir],newdoubled=;
if(dir!=newdir){//若方向不一致,两条边都要加倍
if(!doubled)//对于前一条边分两种情况讨论:已经double(之前已经加速或起步),未double
v+=grid[r][c][inv[dir]];//
newdoubled=;
v+=grid[r][c][newdir];
}
solver.add(ID(r,c,dir,doubled),ID(newr,newc,newdir,newdoubled),v);
//若方向一致,连到newdouble==0的两条边权值相同
//否则,连到newdouble==1的两条边相差grid[r][c][inv[dir]],即分开讨论老边是否已加倍,由于最后求最短路,不影响
}
solver.dijkstra(); int ans=INF;
for(int dir=;dir<;dir++)//从与终点(r2,c2)相连的八个状态中取最小值
if(cango(r2,c2,inv[dir]))
for(int doubled=;doubled<;doubled++)
{
int v=solver.d[ID(r2,c2,dir,doubled)];
if(!doubled)
v+=grid[r2][c2][inv[dir]];
ans=min(ans,v);
} printf("Case %d: ",++kase);
if(ans==INF)
printf("Impossible\n");
else
printf("%d\n",ans);
}
return ;
}
后记:
这里的数组id[][][][],以及函数 ID()的处理很值得学习一下。在处理多状态等复杂情况是很实用。
用这个方法自己写了一道题,一遍就通过了样例,好有成就感,可惜uva在这道题上又挂了= =
UVALive 4128 Steam Roller(最短路(拆点,多状态))的更多相关文章
- UVaLive 4128 Steam Roller (多决策最短路)
题意:给定一个图,r 根横线, c 根竖线.告诉你起点和终点,然后从起点走,每条边有权值,如果是0,就表示无法通行.走的规则是:如果你在下个路要转弯,会使这段路的时间加倍,但是如果一条路同时是这样,那 ...
- UVALive 4128 Steam Roller 蒸汽式压路机(最短路,变形) WA中。。。。。
题意: 给一个由n*m个正方形格子组成的矩形,其中每个格子的边都是可以走的,长度给定,规定:如果在进入该路前需要拐弯,或者走完该路需要拐弯,都是需要付出双倍距离的(每条路最多算2倍).问从起点到终点的 ...
- UVa1078 Steam Roller——拆点+最短路
题目链接 思路 把每个点拆成\(5\)个点\(id(x,y),id(x,y)+n,id(x,y)+2*n,id(x,y)+3*n,id(x,y)+4*n\),分别表示到这个点时的方向为上,右,下,左和 ...
- HDU 4725 The Shortest Path in Nya Graph(最短路拆点)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4725 题意:n个点,某个点属于某一层.共有n层.第i层的点到第i+1层的点和到第i-1层的点的代价均是 ...
- BZOJ 3931 网络吞吐量(最短路+拆点最大流)
3931: [CQOI2015]网络吞吐量 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 1607 Solved: 652 [Submit][St ...
- UVALive 6885 Flowery Trails 最短路枚举
题目连接: http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=129723 题意: 给你一个n点m图的边 1到n有多条最短路 ...
- UVALive 6885 Flowery Trails 最短路
Flowery Trails 题目连接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid= ...
- 【ACM】那些年,我们挖(WA)过的最短路
不定时更新博客,该博客仅仅是一篇关于最短路的题集,题目顺序随机. 算法思想什么的,我就随便说(复)说(制)咯: Dijkstra算法:以起始点为中心向外层层扩展,直到扩展到终点为止.有贪心的意思. 大 ...
- 【bzoj3931】[CQOI2015]网络吞吐量 最短路+最大流
题目描述 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为路由器.为了使数据包最快的到达目的地,路由器需要选择最优的路径转发 ...
随机推荐
- unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor
eclipse启动项目时,提示超时: 解决方案: 修改 workspace\.metadata\.plugins\org.eclipse.wst.server.core\servers.xml文件. ...
- 3563: DZY Loves Chinese - BZOJ
Description神校XJ之学霸兮,Dzy皇考曰JC.摄提贞于孟陬兮,惟庚寅Dzy以降.纷Dzy既有此内美兮,又重之以修能.遂降临于OI界,欲以神力而凌♂辱众生. 今Dzy有一魞歄图,其上有N座祭 ...
- phonegap file操作
phonegap中,有时候需要操作到手机中的文件,这个时候就需要用到phonegap官方提供的插件 file ,英文好的可以直接参考官方文档 首先是安装插件:(需要phonegap 3.0 以上,不止 ...
- java和javascript真的有关系=。=
相同点:1. 内存管理,两者都采用GC来对内存进行回收.因此Java与javascript的内存泄露情况十分相似. 2. 代码编译为机器码后由中间件执行:Java使用前会编译为字节码后由JVM执行,V ...
- Android SDK下载地址
原地址:http://lameck.blog.163.com/blog/static/38811374201262111309677/ Android SDK.ADT.tools等官方下载地址(201 ...
- Oracle index hint syntax
Question: I added an index hint in my query, but the hint is being ignored. What is the correct sy ...
- React vs Angular 2: 冰与火之歌
黄玄 · 3 个月前 本文译自 Angular 2 versus React: There Will Be Blood ,其实之前有人翻译过,但是翻得水平有一点不忍直视,我们不希望浪费这篇好文章. 本 ...
- 2013年山东省第四届ACM大学生程序设计竞赛 Alice and Bob
Alice and Bob Time Limit: 1000ms Memory limit: 65536K 题目描述 Alice and Bob like playing games very ...
- Android AlarmManager的取消
取消alarm使用AlarmManager.cancel()函数,传入参数是个PendingIntent实例. 该函数会将所有跟这个PendingIntent相同的Alarm全部取消,怎么判断两者是否 ...
- C++ Primer笔记整理
1. 迭代器:迭代器是一种对象,它可以看做是游标,用来遍历标准模板库中的部分或者全部元素. 每个迭代器指向容器中确定的地址,此外,迭代器还提供一些基本操作符:*.++.==.!=.=. 2. 模板:是 ...