题解

2 条题解

  • 1
    @ 2018-08-11 17:58:58

    f(i, j)代表从第1个点到第i个点,长度刚好是第1个点到第i个点最短路径的长度加j,路径的数量。如果递归时发现递归到了已经正在递归的点,返回-1。

    #include <cstdio>
    #include <queue>
    #include <vector>
    
    using namespace std;
    
    int T;
    
    int dist[100001];
    
    int f[100001][51];
    bool working[100001][51];
    
    int n, m, k, p;
    
    const int INF = 2100000000;
    
    struct Edge {
        int to;
        int len;
    };
    
    vector<Edge> graph[100001];
    vector<Edge> graph_r[100001];
    
    int get(int node, int l)
    {
        int ans = 0;
        if (l < 0 || l > k) return 0;
        if (working[node][l]) {
            working[node][l] = false;
            return -1;
        }
        if (f[node][l] != -1) {
            return f[node][l];
        }
        working[node][l] = true;
        for (int i = 0; i < graph_r[node].size(); i++) {
            Edge e = graph_r[node][i];
            int val = get(e.to, dist[node] + l - dist[e.to] - e.len);
            if (val == -1) {
                working[node][l] = false;
                return -1;
            }
            ans += val;
            if (ans >= p) ans -= p;
        }
        working[node][l] = false;
        if (node == 1 && l == 0) ans++;
        f[node][l] = ans;
        return ans;
    }
    
    int work(void)
    {
        scanf("%d%d%d%d", &n, &m, &k, &p);
        for (int i = 1; i <= n; i++) {
            graph[i].clear();
            graph_r[i].clear();
        }
        for (int i = 1; i <= m; i++) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            Edge e;
            e.to = b;
            e.len = c;
            graph[a].push_back(e);
            e.to = a;
            graph_r[b].push_back(e);
        }
        for (int i = 1; i <= n; i++) {
            dist[i] = INF;
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= k; j++) {
                f[i][j] = -1;
            }
        }
        dist[1] = 0;
        queue<int> que;
        que.push(1);
        while (!que.empty()) {
            int elem = que.front();
            que.pop();
            for (int i = 0; i < graph[elem].size(); i++) {
                if (dist[graph[elem][i].to] > dist[elem] + graph[elem][i].len) {
                    dist[graph[elem][i].to] = dist[elem] + graph[elem][i].len;
                    que.push(graph[elem][i].to);
                }
            }
        }
        int ans = 0;
        for (int i = 0; i <= k; i++) {
            int val = get(n, i);
            if (val == -1)
                return -1;
            ans += val;
            if (ans >= p) ans -= p;
        }
        return ans;
    }
    
    int main()
    {
        scanf("%d", &T);
        for (int i = 1; i <= T; i++) {
            printf("%d\n", work());
        }
        return 0;
    }
    
    
  • 1
    @ 2018-06-02 18:09:03
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iomanip>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <deque>
    #include <set>
    #include <limits>
    #include <string>
    #include <sstream>
    #include <thread>
    using namespace std;
    
    namespace dts
    {
        typedef long long ll;
        
        struct edge
        {
            ll to,d,next;
            edge()
            {
                to=d=next=0;
            };
            edge(ll tov,ll dv,ll nextv)
            {
                to=tov,d=dv,next=nextv;
            };
        };
        
        ll T;
        ll n,m,t,p,esize,flag;
        ll a[200000+1];
        ll b[200000+1];
        ll c[200000+1];
        ll dis[100000+1];
        ll vis[100000+1];
        ll head1[100000+1];
        ll head2[100000+1];
        ll f[100000+1][50+1+1];
        ll v[100000+1][50+1+1];
        deque<ll> q;
        edge e1[200000+1];
        edge e2[200000+1];
        
        void add(ll x,ll y,ll d)
        {
            esize++;
            e1[esize]=edge(y,d,head1[x]);
            e2[esize]=edge(x,d,head2[y]);
            head1[x]=head2[y]=esize;
        }
        
        void spfa()
        {
            q.clear();
            memset(dis,0x3f,sizeof(dis));
            memset(vis,0,sizeof(vis));
            dis[1]=0;
            for (vis[1]=1,q.push_back(1);!q.empty();)
            {
                ll now=q.front();
                vis[now]=0,q.pop_front();
                for (ll i=head1[now];i;i=e1[i].next)
                {
                    ll to=e1[i].to,d=e1[i].d;
                    if (dis[now]+d<dis[to])
                    {
                        dis[to]=dis[now]+d;
                        if (!vis[to])
                            vis[to]=1,q.push_back(to);
                    }
                }
            }
        }
        
        ll dfs(ll now,ll t)
        {
            if (f[now][t]!=-1)
                return f[now][t];
            v[now][t]=1;
            f[now][t]=0;
            for (ll i=head2[now];i;i=e2[i].next)
            {
                ll to=e2[i].to,d=e2[i].d;
                ll s=dis[now]+t-d-dis[to];
                if (s>=0)
                {
                    if (v[to][s])
                        flag=1;
                    f[now][t]=(f[now][t]+dfs(to,s))%p;
                }
            }
            v[now][t]=0;
            return f[now][t];
        }
        
        ll work()
        {
            spfa();
            memset(f,-1,sizeof(f));
            f[1][0]=1;
            memset(v,0,sizeof(v));
            ll ans=0;
            for (ll i=0;i<=t&&(!flag);i++)
                ans=(ans+dfs(n,i))%p;
            if (!flag)
                dfs(n,t+1);
            if (flag)
                return -1;
            else
                return ans;
        }
        
        void main()
        {
            while (~scanf("%lld",&T))
                for (ll rp=1;rp<=T;rp++)
                {
                    flag=0;
                    scanf("%lld%lld%lld%lld",&n,&m,&t,&p);
                    esize=0;
                    memset(head1,0,sizeof(head1));
                    memset(head2,0,sizeof(head2));
                    for (ll i=1;i<=m;i++)
                    {
                        scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
                        add(a[i],b[i],c[i]);
                    }
                    printf("%lld\n",work());
                }
        }
    }
    
    int main()
    {
        dts::main();
    }
    
    • @ 2018-06-02 18:09:39

      記憶化搜索

  • 1

信息

ID
2030
难度
8
分类
(无)
标签
递交数
438
已通过
63
通过率
14%
被复制
9
上传者