UVA-10917 Walk Through the Forest (dijkstra+DP)

题目大意:n个点,m条边的无向图。一个人从起点到终点按照下面的走法:从A走向B当A到终点的最小距离比B到终点的最小距离大时。问从起点到终点有多少路径方案。

题目分析:先用dijkstra预处理出终点到每个点的最短路,然后将满足行走条件的A、B(除行走条件外,还要满足一个前提,即A、B之间要有边)用一条有向边连起来(A->B),得到一个DAG,动态规划解决。

代码如下:

# include<iostream>
# include<cstdio>
# include<vector>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std;
# define LL long long

const LL INF=0x7fffffffffffffff;
struct Node
{
    int u;
    LL d;
    Node(int _u,LL _d):u(_u),d(_d){}
    bool operator < (const Node &a) const {
        return d>a.d;
    }
};
struct Edge
{
    int to,nxt,w;
};
Edge e[200005];
int head[1005],n,cnt,vis[1005],dp[1005],mp[1005][1005];
LL dist[1005];
vector<int>G[1005];

void add(int u,int v,int w)
{
    e[cnt].to=v;
    e[cnt].w=w;
    e[cnt].nxt=head[u];
    head[u]=cnt++;
}

void dijkstra(int S)
{
    memset(vis,0,sizeof(vis));
    fill(dist,dist+n+1,INF);
    dist[S]=0;
    priority_queue<Node>q;
    q.push(Node(S,0));
    while(!q.empty())
    {
        Node u=q.top();
        q.pop();
        if(vis[u.u])    continue;
        vis[u.u]=1;
        for(int i=head[u.u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(dist[v]>u.d+e[i].w){
                dist[v]=u.d+e[i].w;
                if(!vis[v])
                    q.push(Node(v,dist[v]));
            }
        }
    }
}

int DP(int u)
{
    if(dp[u]!=-1)   return dp[u];
    if(u==2)
        return dp[u]=1;
    int sum=0;
    for(int i=0;i<G[u].size();++i)
        sum+=DP(G[u][i]);
    return dp[u]=sum;
}

int main()
{
    int a,b,c,m;
    while(scanf("%d",&n)&&n)
    {
        cnt=0;
        memset(head,-1,sizeof(head));
        memset(mp,0,sizeof(mp));
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
            mp[a][b]=mp[b][a]=1;
        }

        dijkstra(2);

        for(int i=0;i<=n;++i)   G[i].clear();
        for(int i=1;i<=n;++i){
            for(int j=i+1;j<=n;++j){
                if(!mp[i][j])   continue;
                if(dist[i]>dist[j])
                    G[i].push_back(j);
                if(dist[i]<dist[j])
                    G[j].push_back(i);
            }
        }
        memset(dp,-1,sizeof(dp));
        printf("%d
",DP(1));
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/20143605--pcx/p/4905637.html