标签:包括 img ros 题解 set 输出 好的 个人 add
题目描述
.bmp)
输入
输出
样例输入
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