DP+图论大毒瘤。

推荐这个博客。

先跑两遍最短路,搞掉一些无用点。

然后选出最短路上的边,做拓扑排序。

然后每层DP。

具体看代码。

用到的数组较多,记得清空。

  1 #include <cstdio>
  2 #include <queue>
  3 #include <cstring>
  4 const int N = 100010;
  5
  6 inline void read(int &x) {
  7     x = 0;
  8     char c = getchar();
  9     while(c > '9' || c < '0') {
 10         c = getchar();
 11     }
 12     while(c <= '9' && c >= '0') {
 13         x = (x << 3) + (x << 1) + c - 48;
 14         c = getchar();
 15     }
 16     return;
 17 }
 18
 19 struct Edge {
 20     int nex, len, v;
 21 }edge[N << 1], edge_[N << 1]; int top;
 22
 23 int n, m, K, MO, f[N][52];
 24 int e[N], e_[N], d[N], d_[N];
 25 bool vis[N], use_e[N << 1], use_p[N];
 26 int topo[N], in[N], TOPO;
 27
 28 inline void add(int x, int y, int z) {
 29     edge[++top].v = y;
 30     edge[top].len = z;
 31     edge[top].nex = e[x];
 32     e[x] = top;
 33     edge_[top].v = x;
 34     edge_[top].len = z;
 35     edge_[top].nex = e_[y];
 36     e_[y] = top;
 37     return;
 38 }
 39
 40 inline void SPFA() {
 41     std::queue<int> Q;
 42     memset(vis, 0, sizeof(vis));
 43     memset(d, 0x3f, sizeof(d));
 44     Q.push(1);
 45     d[1] = 0;
 46     vis[1] = 1;
 47     while(!Q.empty()) {
 48         int x = Q.front();
 49         Q.pop();
 50         vis[x] = 0;
 51         for(int i = e[x]; i; i = edge[i].nex) {
 52             int y = edge[i].v;
 53             if(d[y] > d[x] + edge[i].len) {
 54                 d[y] = d[x] + edge[i].len;
 55                 if(!vis[y]) {
 56                     vis[y] = 1;
 57                     Q.push(y);
 58                 }
 59             }
 60         }
 61     }
 62     for(int i = 1; i <= n; i++) {
 63         if(d[i] == 0x3f3f3f3f) {
 64             use_p[i] = 0;
 65         }
 66     }
 67     return;
 68 }
 69
 70 inline void SPFA_() {
 71     std::queue<int> Q;
 72     memset(vis, 0, sizeof(vis));
 73     memset(d_, 0x3f, sizeof(d_));
 74     Q.push(n);
 75     vis[n] = 1;
 76     d_[n] = 0;
 77     while(!Q.empty()) {
 78         int x = Q.front();
 79         Q.pop();
 80         vis[x] = 0;
 81         for(int i = e_[x]; i; i = edge_[i].nex) {
 82             int y = edge_[i].v;
 83             if(d_[y] > d_[x] + edge_[i].len) {
 84                 d_[y] = d_[x] + edge_[i].len;
 85                 if(!vis[y]) {
 86                     vis[y] = 1;
 87                     Q.push(y);
 88                 }
 89             }
 90         }
 91     }
 92     for(int i = 1; i <= n; i++) {
 93         if(d_[i] == 0x3f3f3f3f) {
 94             use_p[i] = 0;
 95         }
 96     }
 97     return;
 98 }
 99
100 inline void solve() {
101     int x, y, z;
102     read(n);
103     read(m);
104     read(K);
105     read(MO);
106     top = 0;
107     memset(e, 0, sizeof(e));
108     memset(e_, 0, sizeof(e_));
109     for(int i = 1; i <= m; i++) {
110         read(x);
111         read(y);
112         read(z);
113         add(x, y, z);
114     }
115     memset(use_p, 1, sizeof(use_p));
116     //printf("use_p %d \n", use_p[2]);
117     SPFA_();
118     SPFA();
119
120     memset(use_e, 0, sizeof(use_e));
121     memset(in, 0, sizeof(in));
122     for(int i = 1; i <= m; i++) {
123         int x = edge_[i].v;
124         int y = edge[i].v;
125         if(use_p[x] && use_p[y] && d[x] + edge[i].len == d[y]) {
126             use_e[i] = 1;
127             in[y]++;
128         }
129     }
130
131     /// topo sort
132     TOPO = 0;
133     std::queue<int> Q;
134     for(int i = 1; i <= n; i++) {
135         if(!in[i]) {
136             Q.push(i);
137         }
138     }
139     while(!Q.empty()) {
140         int x = Q.front();
141         Q.pop();
142         topo[++TOPO] = x;
143         for(int i = e[x]; i; i = edge[i].nex) {
144             if(!use_e[i]) {
145                 continue;
146             }
147             int y = edge[i].v;
148             in[y]--;
149             if(!in[y]) {
150                 Q.push(y);
151             }
152         }
153     }
154     if(TOPO < n) {
155         printf("-1\n");
156         return;
157     }
158
159     /// DP
160     memset(f, 0, sizeof(f));
161     f[1][0] = 1;
162     for(int k = 0; k <= K; k++) {
163         for(int a = 1; a <= n; a++) {
164             int x = topo[a];
165             if(!use_p[x]) {
166                 continue;
167             }
168             for(int i = e[x]; i; i = edge[i].nex) {
169                 int y = edge[i].v;
170                 if(!use_p[y]) {
171                     continue;
172                 }
173                 int temp = d[x] + edge[i].len - d[y] + k;
174                 if(temp > K) {
175                     //printf("temp = %d > K \n", temp);
176                     continue;
177                 }
178                 //printf("f[%d][%d] += f[%d][%d] ", y, temp, x, k);
179                 f[y][temp] += f[x][k];
180                 f[y][temp] %= MO;
181                 //printf("= %d \n", f[y][temp]);
182             }
183         }
184     }
185
186     int ans = 0;
187     for(int i = 0; i <= K; i++) {
188         ans = (ans + f[n][i]) % MO;
189     }
190     printf("%d\n", ans);
191
192     return;
193 }
194
195 int main() {
196     int T;
197     read(T);
198     while(T--) {
199         solve();
200     }
201     return 0;
202 }

AC代码

感觉是我用memset最多的一次了。

有个记忆化搜索的写法,先坑着。

转载于:https://www.cnblogs.com/huyufeifei/p/9649075.html

洛谷P3953 逛公园相关推荐

  1. 洛谷 P3953 逛公园

    原题链接 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 NN 个点 MM 条边构成的有向图,且没有 自环和重边.其中 11 号点是公园的入口,NN 号点是公园的出口,每条边有一个非负权值, 代表 ...

  2. 洛谷P3953 逛公园(dp 拓扑排序)

    题意 题目链接 Sol 去年考NOIP的时候我好像连最短路计数都不会啊qwq.. 首先不难想到一个思路,\(f[i][j]\)表示到第\(i\)个节点,与最短路之差长度为\(j\)的路径的方案数 首先 ...

  3. NOIP2017洛谷P3953:逛公园(分层图最短路、dp、拓扑)

    解析 容易想到dp 先跑一遍最短路把每个点的dis求出来 设计dpu,xdp_{u,x}dpu,x​表示结点u多走了x的方案数 dp按照dis升序排列后,从前到后转移即可 如果有0边,求出只有0边时的 ...

  4. 洛谷 P1638 逛画展

    洛谷 P1638 逛画展 题目链接 题目描述 博览馆正在展出由世上最佳的 M 位画家所画的图画. wangjy想到博览馆去看这几位大师的作品. 可是,那里的博览馆有一个很奇怪的规定,就是在购买门票时必 ...

  5. 洛谷 P3953 [NOIP2017 提高组] 逛公园

    开始刷题单啦~,这部分的洛谷好题作为个人训练记录和以后复习用,有兴趣的可以一起做做 题目链接:P3953 [NOIP2017 提高组] 逛公园 题意都是中文就不翻译了 题解:这是一道记忆化+搜索的题目 ...

  6. Luogu P3953 逛公园

    不管怎么说,这都是一道十分神仙的NOIp题 你可以说它狗,但不可以否认它就是NOIp的难度 首先这道题很显然是道图论题还是一道图论三合一(最短路+拓扑+图上DP) 先考虑最短路,我们分别以\(1\)和 ...

  7. 洛谷P1638 逛画展

    题目描述 博览馆正在展出由世上最佳的 m 位画家所画的图画. 游客在购买门票时必须说明两个数字,a 和 b,代表他要看展览中的第 a 幅至第 b 幅画(包含 a,b)之间的所有图画,而门票的价钱就是一 ...

  8. 洛谷 [P1638 逛画展] (尺取法)

    Link https://www.luogu.org/problemnew/show/P1638 Description  博览馆正在展出由世上最佳的 M 位画家所画的图画.wangjy想到博览馆去看 ...

  9. 洛谷P1638 逛画展-最简单的双指针做法

    思路:定义双指针x和y代表[x,y]区间,初始化x=y=0开始遍历,刚开始时一直增加y直到包含了所有作家的画,然后就从左边x开始删区间有重复作家的画就行.注意不要把任何一个作家的画删到0!! 代码如下 ...

最新文章

  1. Tomaso Poggio:深度学习需要从炼金术走向化学
  2. disp语句怎么格式 matlab_讲座回顾:Matlab使用教程
  3. python3.5怎么安装pip-为python 3.5安装pip
  4. UNIX(多线程):21---线程池实现原理
  5. IT人的好习惯和不良习惯总结
  6. 闪存必须解决的三大问题
  7. c语言sin函数返回nan,C语言入口函数和LD_PRELOAD环境变量
  8. 嘉年华专访 | 国际上智能运维研究
  9. python元编程 实际应用_Python元编程
  10. Activiti 统一身份管理
  11. 十种程序语言帮你读懂大数据的“秘密”,Julia位列其中!(转)
  12. SQLyog-12.4.2版下载,SQLyog最新版下载,SQLyog官网下载,SQLyog Download
  13. PMP22年免费补考来袭 | 送上180道历年PMP考试试题及答案解析
  14. 8926音频录音流程
  15. 大三,在软件工程学习上的感悟
  16. win7设置网络共享(ICS共享)
  17. 七、最短路径——弗洛伊德(Floyd)算法
  18. Magento前台不显示添加的产品
  19. did you register the component correctly? For recursive components, make sure to provide the “name“
  20. 输入学生成绩,输出学生成绩等级,学习成绩>=90且<=100分的同学用A表示,60-89分之间的用B表示,<60且>0分以下的用C表示。其余输入都有误!“

热门文章

  1. 程序员在外面看见bug会想修吗? | 每日趣闻
  2. 太励志!80 后草根创业者自学编程年收入上亿
  3. 卫星数据现已加入 Azure 豪华套餐,在太空向女神表个白?
  4. 高性能计时器Timer的设计(时间轮和时间堆两种方式)
  5. 迁移不是云计算面临的唯一障碍
  6. 以网络安全为例的大数据可视化设计
  7. SDN商用落地:遍地开花不代表全面实现
  8. Spark的transformation和action算子简介
  9. java中native的用法[转]
  10. 闭运算—lhMorpClose