BZOJ2007 NOI2010 海拔 平面图转对偶图 最小割

题面太长啦,请诸位自行品尝—>海拔

 

分析:

  这是我见过算法比较明显的最小割题目了,很明显对于某一条简单路径,海拔只会有一次变换。

  而且我们要最终使变换海拔的边权值和最小。

  我们发现变换海拔相当于将图割开,左上右下两个点分别属于两个不同的集合,那这就是一个很形象的最小割模型。

  我们只需要平面图转转对偶图,将图中每个面变成点,连边跑最短路即可。

转换的细节可能有些麻烦,大家慢慢理解。

代码:

 1 #include<bits/stdc++.h>
 2 #define pi pair<int,int>
 3 #define mp(a,b) make_pair(a,b)
 4 #define ms(a,x) memset(a,x,sizeof(a))
 5 using namespace std;
 6 const int N=250005;int S,T,ans;
 7 struct node{int y,z,nxt;}e[N*8];
 8 priority_queue<pi>q;int h[N],c=1;
 9 int d[N],vis[N],n,m,nm[505][505];
10 void add(int x,int y,int z){
11     e[++c]=(node){y,z,h[x]};h[x]=c;
12 } int main(){
13     scanf("%d",&n);S=0;T=n*n+1;
14     for(int i=1;i<=n;i++)
15     nm[0][i]=nm[i][n+1]=S,
16     nm[i][0]=nm[n+1][i]=T;
17     for(int i=1;i<=n;i++)
18     for(int j=1;j<=n;j++)
19     nm[i][j]=n*(i-1)+j;
20     for(int i=0;i<=n;i++)
21     for(int j=1,x;j<=n;j++)
22     scanf("%d",&x),add(nm[i][j],nm[i+1][j],x);
23     for(int i=1;i<=n;i++)
24     for(int j=0,x;j<=n;j++)
25     scanf("%d",&x),add(nm[i][j+1],nm[i][j],x);
26     for(int i=0;i<=n;i++)
27     for(int j=1,x;j<=n;j++)
28     scanf("%d",&x),add(nm[i+1][j],nm[i][j],x);
29     for(int i=1;i<=n;i++)
30     for(int j=0,x;j<=n;j++)
31     scanf("%d",&x),add(nm[i][j],nm[i][j+1],x);
32     ms(d,0x3f);d[S]=0;q.push(mp(0,S));
33     while(!q.empty()){
34         int x=q.top().second;q.pop();
35         if(vis[x]) continue;vis[x]=1;
36         for(int i=h[x],y;i;i=e[i].nxt)
37         if(d[y=e[i].y]>d[x]+e[i].z)
38         d[y]=d[x]+e[i].z,q.push(mp(-d[y],y));
39     } printf("%d\n",d[T]);return 0;
40 }
对偶图转换+最小割

 

posted @ 2019-01-10 21:35  杜宇一声  阅读(147)  评论(0编辑  收藏  举报