uva10917

题意实际上是在原图中对于一条边(a,b)如果d[a] > d[b]则在新图中连b->a的一条边。

最后求有向图的路径总数。

用dp实现。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int maxn = 1005, maxm = maxn * maxn, inf = 1e9;

struct node
{
    int u, d;
    bool operator < (const node& rhs) const
    {
        return d > rhs.d;
    }
};

priority_queue<node> q;

int n, m, tot;

int h[maxn], done[maxn], dis[maxn], vis[maxn], d[maxn];

struct edge
{
    int v, next, w;
}a[maxm], a2[maxm];

int h2[maxn];

int tot2;

void add(int x, int y, int z)
{
    a[tot].v = y;
    a[tot].w = z;
    a[tot].next = h[x];
    h[x] = tot++;
}

void add2(int x, int y, int z)
{
    a2[tot2].v = y;
    a2[tot2].w = z;
    a2[tot2].next = h2[x];
    h2[x] = tot2++;
}

int dp(int u)
{
    if (vis[u]) return d[u];
    vis[u] = 1;
    if (u == 2) return d[2] = 1;
    d[u] = 0;
    for (int i = h2[u]; ~i; i = a2[i].next)
    {
        int v = a2[i].v;
        d[u] += dp(v);
    }
    return d[u];
}

int main()
{
//    freopen("uva10917.in","r",stdin);
    while (scanf("%d%d", &n, &m) && n && m)
    {
        memset(h, -1, sizeof h); tot = 0;
        for (int i = 1; i <= m; i++)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            add(x, y, z); add(y, x, z);
        }
        for (int i = 1; i <= n; i++)
            dis[i] = inf;
        dis[2] = 0;
        q.push((node){2, 0});//题目中说2是这个人的家,也就是终点 
        memset(done, 0 ,sizeof done);
        while (!q.empty())
        {
            node x = q.top(); q.pop();
            int u = x.u;
            if (done[u]) continue;
            done[u] = 1;
            for (int i = h[u]; ~i; i = a[i].next)
            {
                int v = a[i].v;
                if (dis[u] + a[i].w < dis[v])
                {
                    dis[v] = dis[u] + a[i].w;
                    q.push((node){v,dis[v]});
                }
            }
        }
        memset(h2, -1, sizeof h2); tot2 = 0;
        memset(vis, 0, sizeof vis);
        memset(d, 0, sizeof d);
        for (int i = 1; i <= n; i++)
            for (int j = h[i]; ~j; j = a[j].next) 
            {
                int v = a[j].v;
                if (dis[i] < dis[v]) add2(v, i, a[j].w);//把新图搞出来 
            }
        printf("%d\n", dp(1));
    }
    return 0;
}

 

posted @ 2017-11-02 15:52  yohanlong  阅读(147)  评论(0编辑  收藏  举报