[NOIP 2017] 逛公园

[题目链接]

         http://uoj.ac/problem/331

[算法]

        首先,我们预处理出每个点到第N个点的最短路,这等价于在反图上求第N个点到其余点的最短路

        然后,我们用f[u][k]表示从第u个点到第n个点,至多走长度为dist(u,n) + k的路径有多少种走法

        记忆化搜索即可,注意判断是否存在0环

[代码]

        

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define MAXM 200010
#define MAXK 55
const int INF = 2e9;

int i,j,tot,ans,u,v,w,T,N,M,K,P;
int head[MAXN],rhead[MAXN],dist[MAXN];
int f[MAXN][MAXK];
bool visited[MAXN][MAXK];
bool flag;

struct Edge
{
        int to,w,nxt;
} e[MAXM << 1];

inline void addedge(int u,int v,int w)
{
        tot++;
        e[tot] = (Edge){v,w,head[u]};
        head[u] = tot;
        tot++;
        e[tot] = (Edge){u,w,rhead[v]};
        rhead[v] = tot;
}
inline void dijkstra(int s)
{
        int i,v,w,cur;
        priority_queue< pair<int,int> > q;
        static bool visited[MAXN];
        while (!q.empty()) q.pop();
        for (i = 1; i <= N; i++)
        {
                dist[i] = INF;
                visited[i] = false;
        }
        dist[s] = 0;
        q.push(make_pair(0,s));
        while (!q.empty())
        {
                cur = q.top().second;
                q.pop();
                if (visited[cur]) continue;
                visited[cur] = true;
                for (i = rhead[cur]; i; i = e[i].nxt)
                {
                        v = e[i].to;
                        w = e[i].w;
                        if (dist[cur] + w < dist[v])
                        {
                                dist[v] = dist[cur] + w;
                                q.push(make_pair(-dist[v],v));
                        }
                }
        }
}
inline int dp(int now,int k)
{
        int i,v,w,tmp,cnt,ret;
        if (f[now][k] != -1) return f[now][k];
        if (now == N) ret = 1;
        else ret = 0;
        if (visited[now][k]) return -1;
        visited[now][k] = true;
        for (i = head[now]; i; i = e[i].nxt)
        {
                v = e[i].to;
                w = e[i].w;
                tmp = k - (dist[v] + w - dist[now]);
                if (tmp < 0) continue;
                cnt = dp(v,tmp);
                if (cnt == -1) 
                {
                        flag = true;
                        return -1;
                } else ret = (ret + cnt) % P;
        }    
        visited[now][k] = false;
        return f[now][k] = ret;
}

int main() 
{
        
        scanf("%d",&T);
        while (T--)
        {
                scanf("%d%d%d%d",&N,&M,&K,&P);
                tot = 0;
                for (i = 1; i <= N; i++) head[i] = rhead[i] = 0;
                for (i = 1; i <= M; i++)
                {
                        scanf("%d%d%d",&u,&v,&w);
                        addedge(u,v,w);
                }        
                dijkstra(N);
                flag = false;
                for (i = 1; i <= N; i++)
                {
                        for (j = 0; j <= K; j++)
                        {
                                f[i][j] = -1;
                                visited[i][j] = false;
                        }
                }
                ans = dp(1,K);
                if (flag) printf("-1\n");
                else printf("%d\n",ans);
        }
        
        return 0;
    
}

猜你喜欢

转载自www.cnblogs.com/evenbao/p/9359287.html