【BZOJ2007】【NOI2010】海拔 题解

题面:传送门


    这道题比较具有迷惑性,题目中特意说明答案要四舍五入保留到整数,其实只要细心观察就能发现最优解一定是左上角一堆‘ 0 ’,右下角一堆‘ 1 ’,那么答案就为‘ 0 ’和‘ 1 ’的分界线上的所有边权和,求一遍最小割就行了。

    可是,我们需要注意到,点数可能会达到 n 2 = 250000 ,直接跑最大流算法肯定不能在时限内通过。

    参照网上大佬们的题解,我第一次知道还有对偶图这种玩意儿,只要把一个平面图转化成其对应的对偶图,那么此时原图的最小割等于对偶图的最短路长度,这就可以在时限内通过了。

    对偶图和它所对应的平面图的区别就是把面当做点,面的交界处当作边,原图中方向相反的边对偶图中也方向相反,对偶图中对应的边权等于原图中的边权,总体代码还是很好实现的,加上 D i j k s t r a 和堆优化,时间复杂度: Θ ( n 2 l o g 2 n )

    全部代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cstring>
#include<queue> 
using namespace std;
int n;
vector<pair<int,int> >G[250010];
bool vis[250010];
int dis[250010];
priority_queue<pair<int,int> ,vector<pair<int,int> > ,greater<pair<int,int> > >q;
int gtpos(int x,int y)
{
    return (x-1)*n+y;
}
void addedge(int x,int y,int w)
{
    G[x].push_back(make_pair(y,w));
}
void dijkstra()
{
    for(int i=1;i<=n*n+1;i++)dis[i]=2e9;
    q.push(make_pair(0,0));
    for(int i=0;i=n*n+1;i++)
    {
        while(!q.empty() && (vis[q.top().second] || dis[q.top().second]!=q.top().first))q.pop();
        int x=q.top().second;
        q.pop();
        vis[x]=true;
        if(x==n*n+1)return;
        for(int j=0;j<G[x].size();j++)
        {
            int y=G[x][j].first,w=G[x][j].second;
            if(vis[y])continue;
            if(dis[x]+w<dis[y])
            {
                dis[y]=dis[x]+w;
                q.push(make_pair(dis[y],y)); 
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int x;
            scanf("%d",&x);
            if(!i)addedge(gtpos(i+1,j),n*n+1,x);
            else if(i==n)addedge(0,gtpos(i,j),x);
            else addedge(gtpos(i+1,j),gtpos(i,j),x);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            int x;
            scanf("%d",&x);
            if(!j)addedge(0,gtpos(i,j+1),x);
            else if(j==n)addedge(gtpos(i,j),n*n+1,x);
            else addedge(gtpos(i,j),gtpos(i,j+1),x);
        }
    }
    for(int i=0;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int x;
            scanf("%d",&x);
            if(!i)addedge(n*n+1,gtpos(i+1,j),x);
            else if(i==n)addedge(gtpos(i,j),0,x);
            else addedge(gtpos(i,j),gtpos(i+1,j),x);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            int x;
            scanf("%d",&x);
            if(!j)addedge(gtpos(i,j+1),0,x);
            else if(j==n)addedge(n*n+1,gtpos(i,j),x);
            else addedge(gtpos(i,j+1),gtpos(i,j),x);
        }
    }
    dijkstra();
    printf("%d",dis[n*n+1]);
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_42112677/article/details/80404185
今日推荐