[NOIP2017] 逛公园 【最短路】【强连通分量】

题目分析:

首先考虑无数条的情况。出现这种情况一定是一条合法路径经过了$ 0 $环中的点。那么预先判出$ 0 $环中的点和其与$ 1 $和$ n $的距离。加起来若离最短路径不超过$ k $则输出$ -1 $,否则这些点必定不被经过,接着dp后效性消失。由于每条边转移了$ k $次它的起点到终点的状态,所以总时间复杂度为$ O(n+mk) $,可以通过所有数据。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<queue>
  6 #include<vector>
  7 #include<stack>
  8 using namespace std;
  9 
 10 typedef pair<int,int> pr;
 11 
 12 const int maxn = 105000;
 13 
 14 int n,m,k,p;
 15 vector<pair<int,int> > g[maxn],rg[maxn];
 16 vector <int> ng[maxn];
 17 
 18 int dfn[maxn],low[maxn],instack[maxn],scc[maxn],cl;
 19 int f[maxn][52],arr[maxn][52];
 20 stack <int> sta;
 21 
 22 void init(){
 23     memset(dfn,0,sizeof(dfn));
 24     memset(arr,0,sizeof(arr));
 25     memset(low,0,sizeof(low));
 26     memset(instack,0,sizeof(instack));
 27     memset(scc,0,sizeof(scc));
 28     memset(f,0,sizeof(f));
 29     cl = 0;
 30 }
 31 
 32 void tarjan(int now){
 33     low[now] = dfn[now] = ++cl;
 34     sta.push(now);
 35     for(int i=0;i<ng[now].size();i++){
 36     int k = ng[now][i]; if(instack[k]) continue;
 37     if(dfn[k]) { low[now] = min(low[now],dfn[k]); }
 38     else{ tarjan(k); low[now] = min(low[now],low[k]); }
 39     }
 40     if(low[now] == dfn[now]){
 41     stack<int> tpp;int num = 0;
 42     while(true){
 43         int tp = sta.top();sta.pop();tpp.push(tp);num++;
 44         instack[tp] = 1; scc[tp]=1;
 45         if(now == tp) break;
 46     }
 47     if(num == 1) scc[tpp.top()] = 0;
 48     }
 49 }
 50 
 51 void read(){
 52     scanf("%d%d%d%d",&n,&m,&k,&p);
 53     for(int i=1;i<=n;i++) g[i].clear();
 54     for(int j=1;j<=n;j++) ng[j].clear();
 55     for(int j=1;j<=n;j++) rg[j].clear();
 56     for(int i=1;i<=m;i++){
 57     int u,v,w; scanf("%d%d%d",&u,&v,&w);
 58     g[u].push_back(make_pair(v,w));
 59     rg[v].push_back(make_pair(u,w));
 60     if(w == 0) ng[u].push_back(v);
 61     }
 62 }
 63 
 64 int res;
 65 int d[maxn][2];
 66 priority_queue<pr,vector<pr>,greater<pr> > pq;
 67 void solve_dist(){
 68     memset(d,0x3f,sizeof(d));
 69     pq.push(make_pair(0,1));
 70     while(!pq.empty()){
 71     pair<int,int> tp = pq.top();pq.pop();
 72     if(d[tp.second][0] > 1e9) d[tp.second][0] = tp.first;
 73     else continue;
 74     for(int j=0;j<g[tp.second].size();j++){
 75         int nxt = g[tp.second][j].first,data = g[tp.second][j].second;
 76         data += d[tp.second][0];
 77         if(data > d[nxt][0]) continue;
 78         pq.push(make_pair(data,nxt));
 79     }
 80     }
 81     res = d[n][0];
 82     pq.push(make_pair(0,n));
 83     while(!pq.empty()){
 84     pair<int,int> tp = pq.top();pq.pop();
 85     if(d[tp.second][1] > 1e9) d[tp.second][1] = tp.first;
 86     else continue;
 87     for(int j=0;j<rg[tp.second].size();j++){
 88         int nxt = rg[tp.second][j].first,data = rg[tp.second][j].second;
 89         data += d[tp.second][1];
 90         if(data > d[nxt][1]) continue;
 91         pq.push(make_pair(data,nxt));
 92     }
 93     }
 94 }
 95 
 96 void dfs(int now,int lw){
 97     if(arr[now][lw]) return;
 98     int nowd = d[now][0]+lw;arr[now][lw] = 1;
 99     for(int j=0;j<rg[now].size();j++){
100     int nxt = rg[now][j].first,data = rg[now][j].second;
101     if(scc[nxt])continue;
102     int nd = nowd-data; nd -= d[nxt][0];
103     if(nd < 0) continue;
104     if(nd > k) continue;
105     dfs(nxt,nd);
106     f[now][lw] += f[nxt][nd]; f[now][lw] %= p;
107     }
108 }
109 
110 void work(){
111     for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
112     if(scc[1]||scc[n]) {puts("-1");return;}
113     
114     solve_dist();
115     
116     for(int i=1;i<=n;i++)
117     if(scc[i]) if(d[i][0]+d[i][1]<=res+k){puts("-1");return;}
118     
119     f[1][0] = 1;arr[1][0] = 1;int ans = 0;
120     for(int i=0;i<=k;i++) {
121     dfs(n,i);ans += f[n][i]; ans %= p;
122     }
123     printf("%d\n",ans);
124 }
125 
126 int main(){
127     int t; scanf("%d",&t);
128     while(t--){ init(); read(); work(); }
129     return 0;
130 }

猜你喜欢

转载自www.cnblogs.com/Menhera/p/9086027.html