[2018南京预赛]Magical Girl Haze
一、题面
样例输入:
1
5 6 1
1 2 2
1 3 4
2 4 3
3 4 1
3 5 6
4 5 2
样例输出:
3
二、思路
关键词:分层BFS
考试时觉得题干意思很清晰——求可将k条边赋值为0的最短路。起初几个思路正确性均存疑,后来觉得应该要DP于是决定滞后了。。。
正解——分层BFS,个人认为思路与DP有些许相像,同时记录节点及当前已赋值为0的边数,则在跑最短路时(这里用的SPFA),可选择是否将该条边赋值为0,当且仅当已选边<k。
三、代码
1 #include <cstdio> 2 #include <cstring> 3 4 #define MAXN 100005 5 #define MAXM 200005 6 #define MAXK 15 7 #define INF 0x3f3f3f3f 8 9 int T, n, m, k, u, v, w, o, h[MAXN], d[MAXN][MAXK], vis[MAXN][MAXK]; 10 11 struct node { 12 int n, k; 13 } q[MAXN]; 14 15 struct edge { 16 int v, next, w; 17 } e[MAXM]; 18 19 void add(int u, int v, int w) { 20 o++, e[o] = (edge) {v, h[u], w}, h[u] = o; 21 } 22 23 int spfa() { 24 int head = 1, tail = 2; 25 memset(d, INF, sizeof(d)), memset(vis, 0, sizeof(vis)); 26 q[head] = (node) {1, 0}, d[1][0] = 0, vis[1][0] = 1; 27 while (head != tail) { 28 node o = q[head]; 29 vis[o.n][o.k] = 0; 30 for (int x = h[o.n]; x; x = e[x].next) { 31 int v = e[x].v; 32 if (d[v][o.k] > d[o.n][o.k] + e[x].w) { 33 d[v][o.k] = d[o.n][o.k] + e[x].w; 34 if (!vis[v][o.k]) vis[v][o.k] = 1, q[tail++] = (node) {v, o.k}; 35 } 36 if (o.k < k) { 37 if (d[v][o.k + 1] > d[o.n][o.k]) { 38 d[v][o.k + 1] = d[o.n][o.k]; 39 if (!vis[v][o.k + 1]) vis[v][o.k + 1] = 1, q[tail++] = (node) {v, o.k + 1}; 40 } 41 } 42 } 43 head++; 44 } 45 return d[n][k]; 46 } 47 48 int main() { 49 scanf("%d", &T); 50 for (int i = 1; i <= T; i++) { 51 o = 0, memset(h, 0, sizeof(h)); 52 scanf("%d %d %d", &n, &m, &k); 53 for (int j = 1; j <= m; j++) scanf("%d %d %d", &u, &v, &w), add(u, v, w); 54 printf("%d\n", spfa()); 55 } 56 return 0; 57 }
多个子问题着重考虑各种初始化!