洛谷P3953 逛公园
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 逛公园相关推荐
- 洛谷 P3953 逛公园
原题链接 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 NN 个点 MM 条边构成的有向图,且没有 自环和重边.其中 11 号点是公园的入口,NN 号点是公园的出口,每条边有一个非负权值, 代表 ...
- 洛谷P3953 逛公园(dp 拓扑排序)
题意 题目链接 Sol 去年考NOIP的时候我好像连最短路计数都不会啊qwq.. 首先不难想到一个思路,\(f[i][j]\)表示到第\(i\)个节点,与最短路之差长度为\(j\)的路径的方案数 首先 ...
- NOIP2017洛谷P3953:逛公园(分层图最短路、dp、拓扑)
解析 容易想到dp 先跑一遍最短路把每个点的dis求出来 设计dpu,xdp_{u,x}dpu,x表示结点u多走了x的方案数 dp按照dis升序排列后,从前到后转移即可 如果有0边,求出只有0边时的 ...
- 洛谷 P1638 逛画展
洛谷 P1638 逛画展 题目链接 题目描述 博览馆正在展出由世上最佳的 M 位画家所画的图画. wangjy想到博览馆去看这几位大师的作品. 可是,那里的博览馆有一个很奇怪的规定,就是在购买门票时必 ...
- 洛谷 P3953 [NOIP2017 提高组] 逛公园
开始刷题单啦~,这部分的洛谷好题作为个人训练记录和以后复习用,有兴趣的可以一起做做 题目链接:P3953 [NOIP2017 提高组] 逛公园 题意都是中文就不翻译了 题解:这是一道记忆化+搜索的题目 ...
- Luogu P3953 逛公园
不管怎么说,这都是一道十分神仙的NOIp题 你可以说它狗,但不可以否认它就是NOIp的难度 首先这道题很显然是道图论题还是一道图论三合一(最短路+拓扑+图上DP) 先考虑最短路,我们分别以\(1\)和 ...
- 洛谷P1638 逛画展
题目描述 博览馆正在展出由世上最佳的 m 位画家所画的图画. 游客在购买门票时必须说明两个数字,a 和 b,代表他要看展览中的第 a 幅至第 b 幅画(包含 a,b)之间的所有图画,而门票的价钱就是一 ...
- 洛谷 [P1638 逛画展] (尺取法)
Link https://www.luogu.org/problemnew/show/P1638 Description 博览馆正在展出由世上最佳的 M 位画家所画的图画.wangjy想到博览馆去看 ...
- 洛谷P1638 逛画展-最简单的双指针做法
思路:定义双指针x和y代表[x,y]区间,初始化x=y=0开始遍历,刚开始时一直增加y直到包含了所有作家的画,然后就从左边x开始删区间有重复作家的画就行.注意不要把任何一个作家的画删到0!! 代码如下 ...
最新文章
- Tomaso Poggio:深度学习需要从炼金术走向化学
- disp语句怎么格式 matlab_讲座回顾:Matlab使用教程
- python3.5怎么安装pip-为python 3.5安装pip
- UNIX(多线程):21---线程池实现原理
- IT人的好习惯和不良习惯总结
- 闪存必须解决的三大问题
- c语言sin函数返回nan,C语言入口函数和LD_PRELOAD环境变量
- 嘉年华专访 | 国际上智能运维研究
- python元编程 实际应用_Python元编程
- Activiti 统一身份管理
- 十种程序语言帮你读懂大数据的“秘密”,Julia位列其中!(转)
- SQLyog-12.4.2版下载,SQLyog最新版下载,SQLyog官网下载,SQLyog Download
- PMP22年免费补考来袭 | 送上180道历年PMP考试试题及答案解析
- 8926音频录音流程
- 大三,在软件工程学习上的感悟
- win7设置网络共享(ICS共享)
- 七、最短路径——弗洛伊德(Floyd)算法
- Magento前台不显示添加的产品
- did you register the component correctly? For recursive components, make sure to provide the “name“
- 输入学生成绩,输出学生成绩等级,学习成绩>=90且<=100分的同学用A表示,60-89分之间的用B表示,<60且>0分以下的用C表示。其余输入都有误!“