zzuli 2187 我觉得自己跑得很快 (Dijkstra + 链式前向星)

传送门
某大佬zyf出的神题

Description

As we all know, the… 算了,我英语不好,题目很简单,我们有一个N层的数字塔,塔上每一个格子都有一个bad值,下图展示了一个N=4的数字塔:

当我们进入某个格子时就会获得对应的bad值,我们每次只能向下或者向右下移动一个格子。等等,当时讲动态规划用的不就是这个例题,我还记得它的状态转移方程,这是不是太easy了?
那好吧,来增加一点点难度,我们每次不仅可以向下,向右下移动,还可以向左或者向右移动一个格子,但是不能越界。一开始我们的ssh学长在第一行第一列,他想走到最后一行,但是我们的ssh学长不喜欢bad,他想使得走到最后一行时获得的bad值的和最小,当然最后一行的bad值也要算上。
现在他把这个问题交给你,想让你计算出他最小能获得多少bad值,以及他获得最小bad值时是位于最后一行的哪一列。
Input

第一行一个整数N(1<=N<=1000)。
接下来N行,第i行有i个整数wi1 wi2 … wii,wij表示第i行第j列的格子对应的bad值。
Output

一行两个整数,第一个整数是最小的bad值的和,第二个整数是ssh学长最后的位置,只需要输出该位置是第N行的第几列即可。如果答案不唯一,输出列编号最小的位置。
Sample Input

4
1
2 2
3 4 5
4 5 6 7
Sample Output

10 1
HINT

Source

看上去是dp,实际是最短路,,,好像有人dp过了,把每二位点用(i-1)* + j转成点,然后把边连上,脑洞挺大。。不过用读入优化的时候要考虑空格的问题,因为数据每行最后多一个空格

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<string>
#include<algorithm>
#include<queue>

using namespace std;
const int MAX = 1000010;
const int INF = 0x3f3f3f3f;
int num[MAX],head[MAX],N;//直接把点的权值存放到num里面
struct Edge{
    int to,cost;
    int next;
};
struct Edge rng[4*MAX];
int cnt;
void add(int u,int v){
    rng[cnt].to = v;
    rng[cnt].next = head[u];
    head[u] = cnt++;
}
int dis[MAX];
typedef pair<int,int> P;
struct Rule{
    bool operator()(const int &a,const int &b) const{
        return dis[a] > dis[b];
    }
};
void Dijkstra(){
    priority_queue<int,vector<int>,Rule> q;//这里最好重载下吧,我用pair的时候用greater会超时
    fill(dis+1,dis+1+N*N,INF);
    dis[1] = num[1];
    q.push(1);
    while(!q.empty()){
        int x = q.top();q.pop();
        for(int k=head[x];k != -1;k = rng[k].next){
            int to = rng[k].to;
            if(dis[to] > dis[x] + num[to]){
                dis[to] = dis[x] + num[to];
                q.push(to);
            }
        }
    }
}
int main(void){
    scanf("%d",&N);
    memset(head,-1,sizeof(head));
    int u,v;
    for(int i=1;i<=N;i++){
        for(int j=1;j<=i;j++){
            scanf("%d",&num[(i-1)*N+j]);
            u = (i-1)*N + j;//合并与其相连的四个点
            if(j > 1){
                v = (i-1)*N + j-1;
                add(u,v);
            }
            if(j < i){
                v = (i-1)*N + j+1;
                add(u,v);
            }
            v = i*N + j;
            add(u,v);
            v = i*N + j+1;
            add(u,v);
        }
    }
    Dijkstra();
    int f = -1,c = -1;
    for(int i=(N-1)*N+1;i<=N*N;i++){
        if(f == -1 || dis[i] < dis[f]){
            f = i;
            c = i - (N-1)*N;
        }
    }
    printf("%d %d\n",dis[f],c);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值