[説明] NOIP2017パーク(DP)

[説明] NOIP2017パーク(DP)

最初の投稿は27ポイントを切った...私は敗北ではないでしょう...

そのようなアプローチを検討、設定\(D_I \)を表し、最短パスのノードnへのノードから、\、(DP(I、K)が\)を表し\(Iは\)にノード\(N \)を歩きますアップ\(K \)番号スキームの距離。状態の変化は、この辺が最短以上になります行くことは非常にある場合に、もののエッジを列挙するための転送同等。

伝達方程式
\ [DP(I、K)
{Eにおいて(I、U、W)\} = \和_ DP(U、K-(W-(D_I-d_u))\] 直接転送DFSを使用して(決意を思い出しますリング)することができます。

...

...

...

しかし、私たちはおざなりにすることはできません、正確に転送順序は何ですか?

理解することができる:最短逆実行、新しい描画を構築することができる\(G「=(V、 E)\) 前記\(E \)元のエッジのサブセットは、エッジのための\((U 、V)\)と場合にのみあれば\(d_u \ GEのd_vの\)は、(d)は最短の逆配列です。新しい計画、そうでない場合は解無しDAG /ソリューションの無限の数。だから今は、DAGを保証するため、トポロジカルソート後に転送することができます。(1があります)トポロジカルソート順DFSのバックトラックです。

時間複雑度\(O(T(N-MK + NK + \ログM))\) 正当な\(0 \)の側にそれ以上は、この複雑さを先頭することができます。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}
const int maxn=1e5+5;

template<class M>
struct HEAP{
      M data[maxn*2];
      int cnt;
      inline void down(const int&pos){
        for(int t=pos,k;(t<<1)<=cnt;t=k){
          k=t<<1;
          if(k<cnt&&data[k|1]<data[k]) k|=1;
          if(data[t]>data[k]) swap(data[t],data[k]);
          else return;
        }
      }
      inline void up(const int&pos){
        for(int t=pos;t>>1;t>>=1)
          if(data[t]<data[t>>1]) swap(data[t],data[t>>1]);
          else return;
      }
      inline void push(const M&x){data[++cnt]=x,up(cnt);}
      inline void pop(){swap(data[1],data[cnt--]);down(1);}
      inline M top(){return data[1];}
      inline int size(){return cnt;}
};
HEAP< pair<int,int> > q;

struct E{
      int to,nx,w;
      E(){to=nx=w=0;}
      E(const int&x,const int&y,const int&z){to=x; nx=y; w=z;}
}e[maxn<<2];
int head[maxn],cnt,head0[maxn];
inline void add(const int&fr,const int&to,const int&w,int*h=head){e[++cnt]=E(to,h[fr],w),h[fr]=cnt;}
int d[maxn],n,m,k,mod;
typedef pair<int,int> P;

const int inf=1e9;
inline void dij(){
      for(int t=1;t<=n;++t) d[t]=inf;
      q.push((P){d[n]=0,n});
      while(q.size()){
        P now=q.top(); q.pop();
        if(now.first>d[now.second]) continue;
        for(int t=head[now.second];t;t=e[t].nx)
          if(d[e[t].to]>d[now.second]+e[t].w)
            q.push((P){d[e[t].to]=d[now.second]+e[t].w,e[t].to});
      }
}


int dp[55][maxn];
bool usd[55][maxn];
bool in[55][maxn];
int dfs(const int&now,const int&k){
      if(in[k][now])return -1;
      if(usd[k][now]) return dp[k][now];
      dp[k][now]=now==n;
      in[k][now]=usd[k][now]=1;
      for(int t=head0[now];t;t=e[t].nx){
        int g=e[t].w-(d[now]-d[e[t].to]),ret;
        if(g>k)continue;
        if(ret=dfs(e[t].to,k-g),-1==ret) return dp[k][now]=-1;
        dp[k][now]=(dp[k][now]+ret)%mod;
      }
      in[k][now]=0;
      return dp[k][now];
}

int main(){
      int T=qr();
      while(T--){
        cnt=0;
        n=qr(); m=qr(); k=qr(); mod=qr();
        for(register int t=0;t<=n;++t) head[t]=head0[t]=0;
        for(int i=0;i<=k;++i)
          for(register int t=0;t<=n;++t)
            dp[i][t]=usd[i][t]=in[i][t]=0;
        for(int t=1,t1,t2,t3;t<=m;++t)
          t1=qr(),t2=qr(),t3=qr(),add(t2,t1,t3),add(t1,t2,t3,head0);
        dij();
        //for(int t=1;t<=n;++t) printf("%d\n",d[t]);
        printf("%d\n",dfs(1,k));
      }
      return 0;
}

おすすめ

転載: www.cnblogs.com/winlere/p/11614775.html