标签:包括 img ros 题解 set 输出 好的 个人 add
题目描述
输入
输出
样例输入
1
1
2
3
4
5
6
7
8
样例输出
3
题解
最小割转对偶图最短路
首先肯定有:1个点的高度只可能是0或1,且所有“0”、所有“1”都是相连的。即只有两片区域,左上为“0”区域,右下为“1”区域。
那么题目就转化为一个最小割模型。
但是点数太多,直接求最大流会TLE,于是转化为对偶图求解。
具体同 bzoj1001 。
然而这题是有向图,需要考虑方向。
考虑到朝右下的边是s->t方向,而朝左上的边是t->s方向。
所以求对偶图的边时,也需要使用相同的方向,即朝右下的边是s‘->t‘方向,朝左上的边是t‘->s‘方向,如下图所示。
然后跑堆优化Dijkstra即可。
#include <cstdio> #include <cstring> #include <utility> #include <queue> using namespace std; priority_queue<pair<int , int> > q; int head[250010] , to[1003000] , len[1003000] , next[1003000] , cnt , dis[250010] , vis[250010] , n , num[510][510]; void add(int x , int y , int z) { to[++cnt] = y; len[cnt] = z; next[cnt] = head[x]; head[x] = cnt; } int main() { int i , j , x , s , t; scanf("%d" , &n); s = 0 , t = n * n + 1; for(i = 1 ; i <= n ; i ++ ) num[0][i] = num[i][n + 1] = s , num[i][0] = num[n + 1][i] = t; for(i = 1 ; i <= n ; i ++ ) for(j = 1 ; j <= n ; j ++ ) num[i][j] = n * (i - 1) + j; for(i = 0 ; i <= n ; i ++ ) for(j = 1 ; j <= n ; j ++ ) scanf("%d" , &x) , add(num[i][j] , num[i + 1][j] , x); for(i = 1 ; i <= n ; i ++ ) for(j = 0 ; j <= n ; j ++ ) scanf("%d" , &x) , add(num[i][j + 1] , num[i][j] , x); for(i = 0 ; i <= n ; i ++ ) for(j = 1 ; j <= n ; j ++ ) scanf("%d" , &x) , add(num[i + 1][j] , num[i][j] , x); for(i = 1 ; i <= n ; i ++ ) for(j = 0 ; j <= n ; j ++ ) scanf("%d" , &x) , add(num[i][j] , num[i][j + 1] , x); memset(dis , 0x3f , sizeof(dis)); dis[s] = 0; q.push(make_pair(0 , s)); while(!q.empty()) { x = q.top().second , q.pop(); if(vis[x]) continue; vis[x] = 1; for(i = head[x] ; i ; i = next[i]) if(dis[to[i]] > dis[x] + len[i]) dis[to[i]] = dis[x] + len[i] , q.push(make_pair(-dis[to[i]] , to[i])); } printf("%d\n" , dis[t]); return 0; }
【bzoj2007】[Noi2010]海拔 最小割+对偶图+最短路
标签:包括 img ros 题解 set 输出 好的 个人 add
原文地址:http://www.cnblogs.com/GXZlegend/p/6527018.html