2007: [Noi2010]海拔
https://www.lydsy.com/JudgeOnline/problem.php?id=2007
分析:
平面图最小割。
S在左下,T在右上,从S到T的一个路径使得路径右下方全是1,左上方全是0。
一个问题:每个点的高度只能是0/1,所以有些边是一定不能选的,就让它连向S,不影响。
代码:
1 /* 2 平面图最小割 3 */ 4 #include<cstdio> 5 #include<algorithm> 6 #include<cstring> 7 #include<iostream> 8 #include<cctype> 9 #include<queue> 10 using namespace std; 11 typedef long long LL; 12 13 inline int read() { 14 int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch=getchar()) if (ch=='-') f = -1; 15 for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; return x * f; 16 } 17 18 const int N = 250010; 19 struct Edge{ 20 int to, w, nxt; 21 Edge() {} 22 Edge(int a,int b,int c) {to = a, w = b, nxt = c;} 23 }e[2500100]; 24 struct Node{ 25 int u; 26 LL dis; 27 Node() {} 28 Node(int a,LL b) {u = a, dis = b;} 29 bool operator < (const Node &A) const { 30 return dis > A.dis; 31 } 32 }; 33 int head[N]; 34 LL dis[N]; 35 int Enum, n; 36 bool vis[N]; 37 priority_queue<Node> q; 38 39 void add_edge(int u,int v,int w) { 40 e[++Enum] = Edge(v, w, head[u]); head[u] = Enum; 41 // cout << u << " " << v << " " << w << ' '; 42 } 43 44 int get(int i,int j) { 45 return (i - 1) * n + j; 46 } 47 48 int Dijkstra(int S,int T) { 49 for (int i=0; i<=T; ++i) dis[i] = 1e18, vis[i] = false; 50 dis[S] = 0; 51 q.push(Node(S,0)); 52 Node now, nxt; 53 while (!q.empty()) { 54 now = q.top(); q.pop(); 55 int u = now.u; 56 if (vis[u]) continue; 57 vis[u] = true; 58 for (int i=head[u]; i; i=e[i].nxt) { 59 int v = e[i].to; 60 if (dis[v] > dis[u] + e[i].w) { 61 dis[v] = dis[u] + e[i].w; 62 q.push(Node(v,dis[v])); 63 } 64 } 65 } 66 return dis[T]; 67 } 68 69 int main() { 70 n = read(); 71 int S = 0, T = n * n + 1; 72 73 for (int i=1; i<=n+1; ++i) { // 左 -> 右, 下 -> 上 74 for (int j=1; j<=n; ++j) { 75 int w = read(); 76 if (i == 1) add_edge(get(i, j), T, w); 77 else if (i == n + 1) add_edge(S, get(i - 1, j), w); 78 else add_edge(get(i, j), get(i - 1, j), w); 79 } 80 } 81 82 for (int i=1; i<=n; ++i) { // 上 -> 下 , 左 -> 右 83 for (int j=1; j<=n+1; ++j) { 84 int w = read(); 85 if (j == 1) add_edge(S, get(i, j), w); 86 else if (j == n + 1) add_edge(get(i, j - 1), T, w); 87 else add_edge(get(i, j - 1), get(i, j), w); 88 } 89 } 90 91 for (int i=1; i<=n+1; ++i) { // 右 -> 左 , 上 -> 下 92 for (int j=1; j<=n; ++j) { 93 int w = read(); 94 if (i == 1) add_edge(T, get(i, j), w); 95 else if (i == n + 1) add_edge(get(i - 1, j), S, w); 96 else add_edge(get(i - 1, j), get(i, j), w); 97 } 98 } 99 100 for (int i=1; i<=n; ++i) { // 下 -> 上 , 右 - > 左 101 for (int j=1; j<=n+1; ++j) { 102 int w = read(); 103 if (j == 1) add_edge(get(i, j), S, w); 104 else if (j == n + 1) add_edge(T, get(i, j - 1), w); 105 else add_edge(get(i, j), get(i, j - 1), w); 106 } 107 } 108 printf("%d",Dijkstra(S, T)); 109 return 0; 110 }