• P3953 逛公园


    传送门

    花了一个下午才 A 的毒瘤题

    思路:

      这题需要建两个图,一个正向图,一个反向图。

      先在正向图上跑一遍 dijkstar ,计算出每个点到 点1 的最短路径 。

      然后在反向图上开始记忆化搜索:

      - 和动规一样,先定义 f [ i ][ j ] 表示:从 点 1 到 点 i 的距离为 dis [ i ] + j 的方案数。(初始值要为负,不然判断 0环 的时候会出错)

      - 对于每一条反向边(u,v,w)都有 f [ u ][ d ] = ∑ f [ u ][(dis[ u ] + d)-(dis[ v ] + w)] 。

        设 lck_dis = (dis[ u ] + d)-(dis[ v ] + w)。

        仔细分析会发现 lck_dis 就表示 点 u 到 起点 1 的距离。

        这类似于 最短路计数 的转移,因为建的是反向边,所以要从后往前转移。

      - 为了判断是否有毒瘤的 0边,需要开一个布尔数组 flag [ i ][ j ] 判断 dp 值是否被经过 2 次,且没有被确定,那么一定是有 0边 导致的自环。

    Code:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<string>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<deque>
    #include<map>
    #include<set>
    using namespace std;
    #define INF 0x3f
    const int maxn=1e5+7;
    inline int read()
    {
        int xs=0,kr=1;
        char ls;
        ls=getchar();
        while(!isdigit(ls))
        {
            if(ls=='-')
                kr=-1;
            ls=getchar();
        }
        while(isdigit(ls))
        {
            xs=(xs<<1)+(xs<<3)+(ls^48);
            ls=getchar();
        }
        return xs*kr;
    }
    int T,n,m,k,p;
    long long ans;
    int head_dij[maxn],head_dfs[maxn],dis[maxn],f[maxn][61];
    bool bo,vis[maxn],flag[maxn][61];
    priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
    struct hh
    {
        int nex,to,w;
    } t_dij[maxn<<1],t_dfs[maxn<<1];
    inline void clear()
    {
        bo=false;
        memset(head_dij,0,sizeof(head_dij));
        memset(head_dfs,0,sizeof(head_dfs));
        memset(dis,INF,sizeof(dis));
        memset(vis,false,sizeof(vis));
        memset(f,-1,sizeof(f));
    }
    inline void add(int cnt,int nex,int to,int w)
    {
        t_dij[cnt].to=to; t_dij[cnt].w=w;
        t_dij[cnt].nex=head_dij[nex]; head_dij[nex]=cnt;
    
        t_dfs[cnt].to=nex; t_dfs[cnt].w=w;
        t_dfs[cnt].nex=head_dfs[to]; head_dfs[to]=cnt;
    }
    inline void dijkstra(int s)
    {
        dis[s]=0;
        q.push(make_pair(0,s));
        while (!q.empty())
        {
            int u=q.top().second;
            q.pop();
            if (vis[u]) continue;
            vis[u]=true;
            for (int i=head_dij[u];i;i=t_dij[i].nex)
            {
                int v=t_dij[i].to,w=t_dij[i].w;
                if (!vis[v]&&dis[v]>dis[u]+w)
                {
                    dis[v]=dis[u]+w;
                    q.push(make_pair(dis[v],v));
                }
            }
        }
    }
    int dfs(int u,int d)
    {
        if (flag[u][d])
        {
            bo=true;
            return 0;
        }
        if (~f[u][d]) return f[u][d];
        flag[u][d]=true;f[u][d]=0;
        for (int i=head_dfs[u];i;i=t_dfs[i].nex)
        {
            if(bo) break;
            int v=t_dfs[i].to,w=t_dfs[i].w;
            int lck_dis=(dis[u]+d)-(w+dis[v]);
            if (lck_dis>=0) f[u][d]=(f[u][d]+dfs(v,lck_dis))%p;
        }
        flag[u][d]=false;
        if (u==1&&!d) return ++f[u][d];
        return f[u][d];    
    }
    int x,y,z;
    int main()
    {
        //freopen("park.in","r",stdin);
        //freopen("park.out","w",stdout);
        T=read();
        while (T--)
        {
            clear();
            n=read();m=read();k=read();p=read();
            for(int i=1;i<=m;i++)
            {
                x=read();y=read();z=read();
                add(i,x,y,z);
            }
            dijkstra(1);
            ans=dfs(n,0)%p;
            for(int i=1;i<=k;i++)
            {
                if(bo) break;
                ans=(ans+dfs(n,i))%p;
            }
            if(bo) printf("-1
    ");
            else printf("%lld
    ",ans);
        }
    return 0;
    }

    注:在 dfs 中,if ( ~ f [ u ][ d ] ) ⇔ if ( f [ u ][ d ] ≥ 0 ) 。有助于卡常

  • 相关阅读:
    js获取对象的最后一个
    vue UI框架
    从前端和后端两个角度分析jsonp跨域访问(完整实例)
    Ajax跨域访问解决方案
    js中将字符串转换成json的三种方式
    【转载】COM 组件设计与应用(九)——IDispatch 接口 for VC6.0
    【转载】COM 组件设计与应用(八)——实现多接口
    【转载】COM 组件设计与应用(七)——编译、注册、调用
    【转载】COM 组件设计与应用(六)——用 ATL 写第一个组件
    【转载】COM 组件设计与应用(五)——用 ATL 写第一个组件
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9898100.html
Copyright © 2020-2023  润新知