NOIP2017 D1T3公園

見出さ\(K \)が小さい場合、それは設定してもよい(O(NK)\)\を A \(DP \)

まず、図が逆転内蔵\(ダイクストラ\)を取得\は(DIS [I] \)を表し(Iは\)\をする\(N- \)の最短距離。

それは満足しなければならない最短見出さ(D <= DIS <= D + K \)\します

、逆思考の特定のポイントからの出発です、あなたが消費するかもしれない\(K \)余長さの単位、最終的に\(N- \)を

デザイン\(DP \)状態を示します。

\([I]、[J F \]) を表し\(Iは\)\(N-を\) および消費\(J \)番号スキーム余長部を。

状態遷移:

提供側\((U、V)\) 辺の長さ\(W \)

则有\(F [U] [J] + = F [v] [J - (DIS [V] + W - DIS [U])] \)

境界\(F [N-] [0] = 1 \) 残りがある\(0 \)

回答\(\ sum_ Iは= {0} ^ {K} F [1] [I] \)

無限のソリューションの判断:

無限のソリューション場合にのみを有することが判明:

するトータル権利がある(0 \)\リング。

私たちはすることができます(DP \)を\時間に従事する\(VIS \)配列の裁判官は、別の文無限の理解を必要としません。

時間複雑

全体のプロセスは、合計ので、検索のメモリによって実現\(NK \)の状態、各点が列挙\(K \)各エッジは全体列挙した回数、\(K \)倍。

だからの複雑\(O(K(N + M))\)

\(ヒント:\)

  1. そして、移動することが\(N \) その後は、折り返されたので、$ U = $ N際に直接ではなく\(リターン\)
  2. 後があるかもしれません\(N \)ポイント\(0 \)リング、そう\(N \)がリングを判断する方法を指すとき。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#include <cstdlib>
using namespace std;
typedef pair<int, int> PII;
const int N = 100005, M = 400005, S = 51;
int n, m, K, P, f[N][S], dis[N];
int head[N], rhead[N], numE[2];
bool st[N], vis[N][S], ep = false;
struct E {
    int next, v, w;
}e[M], r[M];
//建图
void inline add(E g[], int h[], int u, int v, int w, int p) {
    g[++numE[p]] = (E) { h[u], v, w };
    h[u] = numE[p];
}
//多组数据初始化
void inline init() {
    ep = false;
    memset(dis, 0x3f, sizeof dis);
    memset(st, false, sizeof st);
    numE[0] = numE[1] = 0;
    memset(head, 0, sizeof head);
    memset(rhead, 0, sizeof head);
    memset(f, -1, sizeof f);
}
// Dijkstra 最短路
priority_queue<PII, vector<PII>, greater<PII> > q;
void inline dijkstra() {
    dis[n] = 0; q.push(make_pair(0, n));
    while(!q.empty()) {
        PII u = q.top(); q.pop();
        if(st[u.second]) continue;
        st[u.second] = true;
        for (int i = rhead[u.second]; i; i = r[i].next) {
            int v = r[i].v;
            if(dis[u.second] + r[i].w < dis[v]) {
                dis[v] = dis[u.second] + r[i].w;
                q.push(make_pair(dis[v], v));
            }
        }
    }
}

//记忆化搜索
int dfs(int u, int j) {
    if(vis[u][j]) { ep = true; return 0; }
    if(f[u][j] != -1) return f[u][j];
    
    vis[u][j] = true;
    int &val = f[u][j] = 0;
    for (int i = head[u]; i; i = e[i].next) {
        int v = e[i].v, w = e[i].w;
        //消耗的冗余长度折算
        int k = j - (dis[v] + w - dis[u]);
        if(0 <= k && k <= K) (val += dfs(v, k)) %= P;
        if(ep) return 0;
    }
    
    vis[u][j] = false;
    if(u == n && j == 0) val = 1;
    return val;
}

int main() {
    int T; scanf("%d", &T);
    while(T--) {
        init();
        scanf("%d%d%d%d", &n, &m, &K, &P);
        for (int i = 1, u, v, w; i <= m; i++) {
            scanf("%d%d%d", &u, &v, &w);
            add(e, head, u, v, w, 0); add(r, rhead, v, u, w, 1);
        }
    
        dijkstra();
        
        int ans = 0;
        for (int i = 0; i <= K; i++) {
            memset(vis, false, sizeof vis);
            (ans += dfs(1, i)) %= P;
            if(ep) break; 
        }
        if(ep) puts("-1");
        else printf("%d\n", ans);
    }
}

おすすめ

転載: www.cnblogs.com/dmoransky/p/11717150.html