SDUT 周赛 2498 AOE网上的关键路径

http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2498

题意:汉语...

思路:
比赛的时候是按spfa正向的处理的,然后记录每一点的前一个点如果出现相等去最小的那个。结果wa。赛后才知道这样处理时错的。

比如下图:如果现在终点是6,现在2和3都能使6的距离达到最大且值相同。我们处理的时候会选2,但还是2这条路径却不是最优的,反而3是最有的。

所以我们逆向见图,求一个最短路然后倒着输出就好了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 50007
#define N 10007
using namespace std;
//freopen("din.txt","r",stdin);

struct node
{
    int v,w;
    int next;
}g[M];
int head[N],ct;

struct mm
{
    int x,y;
}p[M];

int pre[N];
int vt[N];
int dis[N];
int id[N],cd[N];
int n;

void add(int u,int v,int w)
{
    g[ct].v = v;
    g[ct].w = w;
    g[ct].next = head[u];
    head[u] = ct++;
}
void spfa(int s)
{
    int i,j;
    for (i = 1; i <= n; ++i)
    {
        dis[i] = -inf;
        vt[i] = false;
        pre[i] = -1;
    }
    queue<int>q;
    q.push(s); dis[s] = 0;
    vt[s] = true;

    while (!q.empty())
    {
        int u = q.front(); q.pop();
        for (i = head[u]; i != -1; i = g[i].next)
        {
            int v = g[i].v;
            int w = g[i].w;
            if (dis[v] < dis[u] + w)
            {
                pre[v] = u;
                dis[v] = dis[u] + w;
                if (!vt[v])
                {
                    vt[v] = true;
                    q.push(v);
                }
            }
            else if (dis[v] == dis[u] + w && pre[v] != -1 && pre[v] > u)
            {
                pre[v] = u;
                if (!vt[v])
                {
                   vt[v] = true;
                    q.push(v);
                }
            }
        }
        vt[u] = false;
    }
}
int main()
{
    //freopen("din.txt","r",stdin);
    int m;
    int i;
    int u,v,w;
    while (~scanf("%d%d",&n,&m))
    {
        CL(head,-1); ct = 0;
        CL(id,0); CL(cd,0);

        for (i = 0; i < m; ++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(v,u,w);
            id[u]++;
            cd[v]++;
        }
        int s,e;
        for (i = 1; i <= n; ++i)
        {
            if (id[i] == 0) s = i;
            if (cd[i] == 0) e = i;
        }
       // printf("%d %d\n",s,e);
        spfa(s);
        printf("%d\n",dis[e]);
        int x = e;
        int len = 0;
        while (x != s)
        {
            printf("%d %d\n",x,pre[x]);
            len++;
            x = pre[x];
        }
    }
    return 0;

}
 

  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值