HN OJ 13375 Flowery Trails (spfa的路径遍历)

本文介绍了一种使用SPFA算法求解特定最短路径问题的方法。通过两次SPFA算法分别从起点到终点和从终点回到起点,找出所有最短路径上的边,并计算这些边的总权重,最后将结果乘以2得到最终答案。

题意:就是要你求出所有最短路径上的边之和,然后把结果乘以2

思路:spfa上有一个定理:对于给定的一条边,如果从源点到该边起点的最短距离+起点到该边的最短距离+该边的权值=最短距离,那么说明该边是最短路上的边!

转自:http://blog.youkuaiyun.com/u012313382/article/details/47400247

#include <cstring>  
#include <cmath>  
#include <queue>  
#include <vector>  
#include <cstdio>  
#include <algorithm>  
using namespace std;  
typedef long long ll;  
const int maxn = 10005;  
const int maxm = 600000;  
const int INF = 0x3f3f3f3f;  
int n, m;  
struct ee{  
    int to;  
    int nxt;  
    int w;  
}edge[maxm];  
  
int head[maxn], tol;  
void init(){  
    memset(head, -1, sizeof head );  
    tol = 0;  
}  
void add(int u, int v, int w){  
    edge[tol].to = v;  
    edge[tol].w = w;  
    edge[tol].nxt = head[u];  
    head[u] = tol++;  
}  
int d1[maxn], d2[maxn];  
bool vis[maxn];  
void spfa(int s, int t, int d[])  
{  
    for(int i=0; i<n; ++i) d[i] = INF;  
    memset(vis, false, sizeof vis );  
    queue<int> q;  
    q.push(s);  
    d[s] = 0;  
    vis[s] = true;  
    while(!q.empty()){  
        int u = q.front(); q.pop();  
        vis[u] = false;  
        for(int i=head[u]; ~i; i=edge[i].nxt){  
            int &v = edge[i].to;  
            int &cost = edge[i].w;  
            if(d[v] > d[u] + cost){  
                d[v] = d[u] + cost;  
                if(!vis[v]){  
                    vis[v] = true;  
                    q.push(v);  
                }  
            }  
        }  
    }  
}  
void solve()  
{  
    int s = 0, t = n-1;  
    spfa(s, t, d1);  
    spfa(t, s, d2);  
    ll ans = 0;  
    int minn = d1[t];  
    for(int u=0;u<n;u++)  
    {  
        for(int i=head[u];~i;i=edge[i].nxt)  
        {  
            int &v=edge[i].to;  
            int &cost=edge[i].w;  
            if(d1[u]+d2[v]+cost==minn)  
            {  
                ans+=cost;  
            }  
        }  
    }  
    printf("%I64d\n", ans*2);  
}  
int main(){  
    int u, v, l;  
    while(~scanf("%d%d", &n, &m))  
    {  
        init();  
        for(int i=0; i<m; ++i){  
            scanf("%d%d%d", &u, &v, &l);  
            add(u, v, l);  
            add(v, u, l);  
        }  
        solve();  
    }  
    return 0;  
}  


### 关于东华大学OJ平台中二维数组从右上到左下遍历的解题思路 对于给定的二维数组,要实现从右上角至左下的遍历方式,通常涉及对角线方向的数据访问模式。这种特定路径上的元素处理可以通过调整索引来完成。 在提供的代码片段中,存在一些逻辑用于计算两条特殊对角线上元素乘积与商之和的操作[^1]: ```cpp for(j=0;j<m;j++) { x1=a[j][j]; // 这就是左上到右下的元素值,易找 for(i=0;i<m;i++) { if((m-1)==i+j) { x2=a[i][j];//这是左下到右上的元素 break; } } } ``` 然而,这段代码主要关注的是两个主对角线(即从左上到右下以及从右上到左下),而不是整个矩阵按指定路线遍历的方法。为了真正实现从右上往左下的遍历并获取相应位置的数值,可以采用如下方法: #### 方法一:基于行列坐标的转换 通过改变循环结构来适应新的遍历顺序。具体来说,在外层循环控制当前所处的斜率k(即`row + col = const`),内层则迭代满足此条件的所有(row, col)组合。 ```cpp #include <iostream> using namespace std; int main() { int n; cin >> n; // 输入方阵大小n*n int matrix[n][n]; // 填充matrix... for(int k = 0; k < 2 * n - 1; ++k){ for(int row = max(0, k-(n-1)); row <= min(k, n-1); ++row){ int col = k - row; cout << "Element at (" << row << ", " << col << ") is: " << matrix[row][col]<< endl; } } return 0; } ``` 这种方法能够有效地按照从右上向左下的轨迹读取每一个元素,并且适用于任意尺寸的方形矩阵。 #### 方法二:利用辅助数据结构存储结果后再输 另一种策略是创建一个新的列表或其他容器类型用来保存沿所需路径提取来的元素,最后再统一打印来。这种方式可能更直观但也稍微增加了空间复杂度。 上述两种方案都可以很好地解决如何在一个二维数组执行从右上方移动到左下方的任务。选择哪种取决于实际应用场景和个人偏好。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值