NOI2014 魔法森林 day1t2 SPFA
这道题做法还是很多的,至少有人用最优性剪枝当场A掉了。我只有50分的暴力分(写丑了),SB我不会LCT,先写一下SPFA的神思路做法(说白了还是我SB),LCT以后定补。ORZ想出来的人(hq大神)。最近总感觉考试时没有发挥出全力,考完后一想才发现做法其实还是很好想的。
题意:给一个节点n边m的图,每条边有两个权值a和b,要从1选择两个数x,y出发通过\(a \le x,\ \ b \le y\)的边走到n,求最小的x+y。
想想What's SPFA?最短路?但是我们可以利用松弛操作找到特点两点间的边的最大值。用dis数组来保存从1点到当前点的路径上最大的b称为当前点花费b。做法的精妙之处在于:我们可以从小到大枚举x,之前能到达的点,现在仍然能到达,所以不用管x;如果SPFA时不清空dis数组,里面保存的就是在之前的较小的x的情况下能走到的点的花费b,现在有可能会通过走新边来减小b,新边就是权值恰好为a的边,每次取有这样的边的点进行SPFA即可。
真是一道巧妙的题!
1 //{HEADS 2 #define FILE_IN_OUT 3 #define debug 4 #include <cstdio> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cmath> 8 #include <ctime> 9 #include <algorithm> 10 #include <iostream> 11 #include <fstream> 12 #include <vector> 13 #include <stack> 14 #include <queue> 15 #include <deque> 16 #include <map> 17 #include <set> 18 #include <bitset> 19 #include <complex> 20 #include <string> 21 #define REP(i, j) for (int i = 1; i <= j; ++i) 22 #define REPI(i, j, k) for (int i = j; i <= k; ++i) 23 #define REPD(i, j) for (int i = j; 0 < i; --i) 24 #define STLR(i, con) for (int i = 0, sz = con.size(); i < sz; ++i) 25 #define STLRD(i, con) for (int i = con.size() - 1; 0 <= i; --i) 26 #define CLR(s) memset(s, 0, sizeof s) 27 #define SET(s, v) memset(s, v, sizeof s) 28 #define mp make_pair 29 #define pb push_back 30 #define PL(k, n) for (int i = 1; i <= n; ++i) { cout << k[i] << ' '; } cout << endl 31 #define PS(k) STLR(i, k) { cout << k[i] << ' '; } cout << endl 32 using namespace std; 33 #ifdef debug 34 #ifndef ONLINE_JUDGE 35 const int OUT_PUT_DEBUG_INFO = 1; 36 #endif 37 #endif 38 #ifdef ONLINE_JUDGE 39 const int OUT_PUT_DEBUG_INFO = 0; 40 #endif 41 #define DG if(OUT_PUT_DEBUG_INFO) 42 typedef long long LL; 43 typedef double DB; 44 typedef pair<int, int> i_pair; 45 const int INF = 0x3f3f3f3f; 46 //} 47 48 const int maxn = 50000 + 10; 49 const int maxm = 100000 + 10; 50 const int maxe = maxm * 2; 51 /*{ 前向星*/ 52 struct Edge { 53 int edge; 54 int head[maxn], to[maxe], next[maxe], la[maxe], lb[maxe]; 55 Edge() { 56 edge = 0; 57 memset(head, -1, sizeof head); 58 } 59 void addedge(int u, int v, int a, int b) { 60 to[edge] = v; 61 next[edge] = head[u]; 62 la[edge] = a; 63 lb[edge] = b; 64 head[u] = edge++; 65 } 66 }E; 67 /*}*/ 68 int n, m; 69 70 int dis[maxn]; 71 queue<int> Q; 72 vector<int> p[maxn]; 73 bitset<maxn> vis; 74 75 void spfa(int u, int a) { 76 Q.push(u); 77 vis.reset(); 78 vis[u] = 1; 79 while(!Q.empty()) { 80 int v = Q.front(); Q.pop(); 81 vis[v] = 0; 82 for(int i = E.head[v]; i != -1; i = E.next[i]) { 83 if(E.la[i] <= a && max(dis[v], E.lb[i]) < dis[E.to[i]]) { 84 dis[E.to[i]] = max(dis[v], E.lb[i]); 85 if(!vis[E.to[i]]) { 86 Q.push(E.to[i]); 87 vis[E.to[i]] = 1; 88 } 89 } 90 } 91 } 92 } 93 94 int main() { 95 //FILE_INIT("forest"); 96 freopen("forest.in", "r", stdin); 97 freopen("forest.out", "w", stdout); 98 99 scanf("%d%d", &n, &m); 100 int Max = -INF; 101 REP(i, m) { 102 int u, v, a, b; 103 scanf("%d%d%d%d", &u, &v, &a, &b); 104 E.addedge(u, v, a, b); 105 E.addedge(v, u, a, b); 106 p[a].pb(u); 107 p[a].pb(v); 108 Max = max(Max, a); 109 } 110 int ans = INF; 111 SET(dis, INF); 112 dis[1] = 0; 113 REP(i, Max) { 114 STLR(j, p[i]) { 115 spfa(p[i][j], i); 116 } 117 if(dis[n] != INF) { 118 ans = min(ans, dis[n] + i); 119 } 120 } 121 if(ans == INF) { 122 printf("%d\n", -1); 123 } else { 124 printf("%d\n", ans); 125 } 126 127 return 0; 128 }
人的一切痛苦,本质上都是对自己的无能的愤怒。