luogu2046 海拔

题目链接[NOI2010]海拔

  • 首先有个性质就是海拔只会有\(0\)\(1\)两种。

  • 证明:海拔下降和人数乘积为总消耗,确定了海拔下降总数,如果有个地方可以使得单位消耗最小,那么全部消耗不会更劣。

  • 也就是求一个最小割,转化成对偶图。

  • 左边是\(t\),右边是\(s\),上面是\(s\),下面是\(t\),这样保证了一条合法路径一定隔开了整个格子。

  • 相邻格子连边权,上到下连左,左到右连下,其他相反,跑最短路即可。

  • 代码:

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define R register int
#define ll long long 
using namespace std;
const int N=400001;
const int yl=501;
const int M=5000001;
int cnt,n,u,s,t,tot,nt[M],to[M],hd[N],w[M],idx[yl][yl],Dis[N],vis[N];
void link(R f,R t,R d){nt[++cnt]=hd[f],to[cnt]=t,w[cnt]=d,hd[f]=cnt;}
int gi(){
    R x=0,k=1;char c=getchar();
    while((c<'0'||c>'9')&&c!='-')c=getchar();
    if(c=='-')k=-1,c=getchar();
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*k;
}
struct ip{int val,id;};
int operator < (ip x,ip y){return x.val>y.val;}
priority_queue<ip>Q;
int dij(){
    while(!Q.empty())Q.pop();
    memset(Dis,0x7f,sizeof(Dis));
    Dis[s]=0,Q.push((ip){0,s});
    while(!Q.empty()){
        ip S=Q.top();Q.pop();
        if(vis[S.id])continue;vis[S.id]=1;
        if(S.id==t)return Dis[t];
        for(R k=hd[S.id];k;k=nt[k])
            if(Dis[to[k]]>Dis[S.id]+w[k]){
                Dis[to[k]]=Dis[S.id]+w[k];
                Q.push((ip){Dis[to[k]],to[k]});
            }
    }
    return Dis[t];
}
int main(){
    n=gi();
    for(R i=1;i<=n;++i)
        for(R j=1;j<=n;++j)
            idx[i][j]=(++tot);
    s=tot+1,t=tot+2;
    
    for(R i=1;i<=n;++i)
        u=gi(),link(s,idx[1][i],u);
    for(R i=2;i<=n;++i)
        for(R j=1;j<=n;++j)
            u=gi(),link(idx[i-1][j],idx[i][j],u);
    for(R i=1;i<=n;++i)
        u=gi(),link(idx[n][i],t,u);
    //bei nan

    for(R i=1;i<=n;++i){
        u=gi(),link(idx[i][1],t,u);
        for(R j=1;j<n;++j)
            u=gi(),link(idx[i][j+1],idx[i][j],u);
        u=gi(),link(s,idx[i][n],u);
    }
    //xi dong
    for(R i=1;i<=n;++i)u=gi();
    for(R i=2;i<=n;++i)
        for(R j=1;j<=n;++j)
            u=gi(),link(idx[i][j],idx[i-1][j],u);
    for(R i=1;i<=n;++i)u=gi();
    //nan bei
    for(R i=1;i<=n;++i){
        u=gi();
        for(R j=1;j<n;++j)
            u=gi(),link(idx[i][j],idx[i][j+1],u);
        u=gi();
    }
    printf("%d\n",dij());
    return 0;
}

posted @ 2018-10-17 20:05  Tyher  阅读(147)  评论(0编辑  收藏  举报