洛谷P1608路径统计

题目

这个提示一个简单的最短路计数,除了用数组存上最短路的个数的做法以外,还有可以在得出最短路之后,搜索加剪枝的方法来通过该题。

可以反向搜索用A*的方法来通过,但是这个题的去重十分的恶心,需要一些玄学操作。

\(Code\)

// luogu-judger-enable-o2
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstdlib>
using namespace std;
struct cym {
    int to, len, nex;
}e[6000010], ed[6000010];

int lin[100100], lind[100100], vis[100100], dis[100100], dist[100100], map[2010][2010], n, m, minn = 2147483647, ans, cnt;
inline void add(int f, int t, int l)
{               
    e[++cnt].to = t;
    e[cnt].len = l;
    e[cnt].nex = lin[f];
    lin[f] = cnt;
    ed[cnt].to = f;
    ed[cnt].len = l;
    ed[cnt].nex = lind[t];
    lind[t] = cnt;
}   
void dfs(int now, int sum)
{
    if (now == n && sum == minn)
    {
        ans++;
        return;
    }
    if (now == n || dist[now] + sum > minn)
        return;
    if (sum >= minn) return;
    for (int i = lin[now]; i; i = e[i].nex)
    {
        dfs(e[i].to, sum + e[i].len);   
    }   
}
inline void spfa()
{   
    queue <int> q;
    for (int i = 2; i <= n; i++)
        dis[i] = 2147483647;
    dis[1] = 0;
    q.push(1);
    while (!q.empty())
    {
        int cur = q.front();
        q.pop(), vis[cur] = 0;
        for (int i = lin[cur]; i; i = e[i].nex)
        {
            int to = e[i].to;
            if (dis[cur] + e[i].len < dis[to])
            {
                dis[to] = dis[cur] + e[i].len;
                if (!vis[to])
                    vis[to] = 1, q.push(to);
            }
        }
    }
}   
inline void spfad()
{
    memset(vis, 0, sizeof(vis));
    queue <int> q;
    for (int i = 1; i <= n; i++)
        dist[i] = 2147483647;
    dist[n] = 0;
    q.push(n);
    while (!q.empty())
    {
        int cur = q.front();
        q.pop(), vis[cur] = 0;
        for (int i = lind[cur]; i; i = ed[i].nex)
        {
            int to = ed[i].to;
            if (dist[cur] + ed[i].len < dist[to])
            {
                dist[to] = dist[cur] + ed[i].len;
                if (!vis[to])
                    vis[to] = 1, q.push(to);
            }
        }
    }
}
int main()
{   
//  freopen("hh.txt", "r", stdin);
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        if (map[a][b] == 0)
            map[a][b] = 214746;
        if (map[a][b] <= c) continue;
        add(a, b, c);
        map[a][b] = c;
    }
    spfa();
    spfad();
    /*for (int i = 1; i <= n; i++)
    {
        printf("%d ", dist[i]);
    }
    return 0;*/
    minn = dis[n];
    dfs(1, 0);
    if (m == 0 || minn == 2147483647)
        printf("No answer"), exit(0);
    printf("%d %d", minn, ans);
}   

转载于:https://www.cnblogs.com/liuwenyao/p/10420695.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值