p2046 [NOI2010]海拔

传送门

分析

我们不难想到所有点的海拔要么是0要么是1

所以跑最小割即可

但是时间复杂度不行

于是转化为对偶图的最短路

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define int long long
int n,m,d[300100],vis[300100],s,t;
int head[2000100],to[2000100],nxt[2000100],w[2000100],cnt;
priority_queue<pair<int,int> >q;
inline void add(int x,int y,int z){
    nxt[++cnt]=head[x];
    head[x]=cnt;
    to[cnt]=y;
    w[cnt]=z;
}
inline int getwh(int x,int y){
    if(x==n||y==0)return s;
    if(x==0||y==n)return t;
    return (x-1)*(n-1)+y;
}
inline void dij(){
    memset(d,0x3f,sizeof(d));
    q.push(make_pair(0,s));d[s]=0;
    while(!q.empty()){
      int x=q.top().second;q.pop();
      if(vis[x])continue;vis[x]=1;
      for(int i=head[x];i;i=nxt[i]){
          int y=to[i];
          if(d[y]>d[x]+w[i]){
            d[y]=d[x]+w[i];
            q.push(make_pair(-d[y],y));
          }
      }
    }
}
signed main(){
    int i,j,k;
    scanf("%lld",&n);
    n++;
    s=n*n+20,t=n*n+21;
    for(i=1;i<=n;i++)
      for(j=1;j<n;j++){
           int x;
           scanf("%lld",&x);
           add(getwh(i,j),getwh(i-1,j),x);
      }
    for(i=1;i<n;i++)
      for(j=1;j<=n;j++){
           int x;
           scanf("%lld",&x);
           add(getwh(i,j-1),getwh(i,j),x);
      }
    for(i=1;i<=n;i++)
      for(j=1;j<n;j++){
           int x;
           scanf("%lld",&x);
           add(getwh(i-1,j),getwh(i,j),x);
      }
    for(i=1;i<n;i++)
      for(j=1;j<=n;j++){
           int x;
           scanf("%lld",&x);
           add(getwh(i,j),getwh(i,j-1),x);
      }
    dij();
    printf("%lld
",d[t]);
    return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/10354705.html