zoukankan      html  css  js  c++  java
  • luogu3953 [NOIp2017]逛公园 (tarjan+dijkstra+记忆化搜索)

    先跑一边dijkstra算出从1到i的最短距离dis[i]

    然后建反向边 从n开始记忆化搜索,(p,k)表示1到p的距离=dis[p]+k的方案数

    答案就是$sumlimits_{i=0}^{k}{(n,i)}$

    考虑0环,如果我记搜的时候搜到了0环,那答案就是-1,可以先用tarjan处理一下0边 看看有哪些点在零环上

    (其实也可以开个栈 做到(p,k)的时候看(p,k)是不是已经在栈中了 如果是那就是-1)

      1 #include<bits/stdc++.h>
      2 #define CLR(a,x) memset(a,x,sizeof(a))
      3 using namespace std;
      4 typedef long long ll;
      5 typedef pair<int,int> pa;
      6 const int maxn=1e5+10,maxm=2e5+10,maxk=55;
      7 
      8 inline ll rd(){
      9     ll x=0;char c=getchar();int neg=1;
     10     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
     11     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
     12     return x*neg;
     13 }
     14 
     15 struct Edge{
     16     int b,l,ne;
     17 }eg[maxm],neg[maxm];
     18 struct Node{
     19     int p,k,n;
     20     Node(int a=0,int b=0,int c=0){p=a,k=b,n=c;}
     21 };
     22 int egh[maxn],negh[maxn],ect,nect;
     23 int dis[maxn],f[maxn][maxk];
     24 int dfn[maxn],tot,low[maxn],stk[maxn],sh;
     25 int N,M,K,P;
     26 bool in0[maxn],instk[maxn],flag[maxn];
     27 
     28 inline void adeg(int a,int b,int c){
     29     eg[++ect].b=b,eg[ect].l=c,eg[ect].ne=egh[a],egh[a]=ect;
     30     neg[++nect].b=a,neg[nect].l=c,neg[nect].ne=negh[b],negh[b]=nect;
     31 }
     32 
     33 void tarjan(int x){
     34     dfn[x]=low[x]=++tot,instk[x]=1,stk[++sh]=x;
     35     for(int i=egh[x];i;i=eg[i].ne){
     36         if(eg[i].l) continue;
     37         int b=eg[i].b;
     38         if(!dfn[b]) tarjan(b),low[x]=min(low[x],low[b]);
     39         else if(instk[b]) low[x]=min(low[x],dfn[b]);        
     40     }
     41     if(dfn[x]==low[x]){
     42         int n=0;
     43         for(int i=sh;stk[i]!=x;i--) n++; 
     44         while(1){
     45             instk[stk[sh]]=0;
     46             in0[stk[sh]]=n>0;
     47             if(stk[sh--]==x) break;
     48         }
     49     }
     50 }
     51 
     52 priority_queue<pa,vector<pa>,greater<pa> > q;
     53 inline void dijkstra(){
     54     while(!q.empty()) q.pop();
     55     CLR(flag,0);CLR(dis,63);dis[1]=0;
     56     q.push(make_pair(0,1));
     57     while(!q.empty()){
     58         int p=q.top().second;q.pop();
     59         if(flag[p]) continue;
     60         flag[p]=1;
     61         for(int i=egh[p];i;i=eg[i].ne){
     62             int b=eg[i].b;
     63             if(dis[b]>dis[p]+eg[i].l){
     64                 dis[b]=dis[p]+eg[i].l;
     65                 q.push(make_pair(dis[b],b));
     66             }
     67         }
     68     }
     69 }
     70 
     71 inline int solve(int x,int y){
     72     // if(f[x][y]>=0) printf("get%d %d %d
    ",x,y,f[x][y]);
     73     if(y<0||y>K) return 0;
     74     if(in0[x]) return -1;
     75     if(f[x][y]>=0) return f[x][y];
     76     f[x][y]=0;
     77     for(int i=negh[x];i;i=neg[i].ne){
     78         int b=neg[i].b;
     79         int re=solve(b,dis[x]-dis[b]+y-neg[i].l);
     80         if(re==-1) return -1;
     81         f[x][y]+=re,f[x][y]%=P;
     82     }
     83     return f[x][y];
     84 }
     85 
     86 int main(){
     87     int i,j,k;
     88     for(int T=rd();T;T--){
     89         N=rd(),M=rd(),K=rd(),P=rd();
     90         CLR(egh,0);ect=0;
     91         CLR(negh,0);nect=0;
     92         for(i=1;i<=M;i++){
     93             int a=rd(),b=rd(),c=rd();
     94             adeg(a,b,c);
     95         }
     96         CLR(dfn,0);CLR(instk,0);tot=0;CLR(in0,0);
     97         for(i=1;i<=N;i++)
     98             if(!dfn[i]) tarjan(i);
     99         dijkstra();
    100         CLR(f,-1);
    101         f[1][0]=1;int ans=0;
    102         for(i=0;i<=K;i++)
    103             ans+=solve(N,i),ans%=P;
    104         printf("%d
    ",ans<0?-1:ans);
    105     }
    106     
    107     return 0;
    108 }
  • 相关阅读:
    C++中两种获取UUID的方法(编程)
    在python中发送自定义消息
    lib,dll的位置
    GetWindowText
    SuspendThread and ResumeThread
    创建线程检查按钮的状态
    C++检测句柄的权限
    POJ2186 强联通
    POJ2186 强联通
    POJ 1201 差分约束(集合最小元素个数)
  • 原文地址:https://www.cnblogs.com/Ressed/p/9897011.html
Copyright © 2011-2022 走看看