Luogu2046 NOI2010 海拔 平面图、最小割、最短路

传送门


首先一个不知道怎么证的结论:任意点的\(H\)只会是\(0\)\(1\)

那么可以发现原题的本质就是一个最小割,左上角为\(S\),右下角为\(T\),被割开的两个部分就是\(H=0\)\(H=1\)的部分

直接上Dinic似乎有90pts

然后可以发现原图是一个经典的平面图

于是将平面图最小割转化成对偶图最短路模型,然后堆优化Dijkstra即可。

关于平面图最小割转化为对偶图最短路可以看这个

#include<bits/stdc++.h>
#define id(i , j) (((i) - 1) * N + (j))
#define INF 0x3f3f3f3f
#define st first
#define nd second
#define PII pair < int , int >
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c) && c != EOF){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    if(c == EOF)
        exit(0);
    while(isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ '0');
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 255010 , MAXM = 2050010;
struct Edge{
    int end , upEd , w;
}Ed[MAXM];
int head[MAXN] , dis[MAXN];
int N , S , T , cntEd = 1;
priority_queue < PII > q;

inline void addEd(int a , int b , int c){
    Ed[++cntEd].end = b;
    Ed[cntEd].upEd = head[a];
    Ed[cntEd].w = c;
    head[a] = cntEd;
}

inline void Dijk(){
    memset(dis , 0x3f , sizeof(dis));
    dis[S] = 0;
    q.push(PII(0 , S));
    while(!q.empty()){
        PII t = q.top();
        q.pop();
        if(-t.st > dis[t.nd])
            continue;
        if(t.nd == T)
            return;
        for(int i = head[t.nd] ; i ; i = Ed[i].upEd)
            if(dis[Ed[i].end] > dis[t.nd] + Ed[i].w){
                dis[Ed[i].end] = dis[t.nd] + Ed[i].w;
                q.push(PII(-dis[Ed[i].end] , Ed[i].end));
            }
    }
}

void input(){
    N = read();
    T = id(N , N) + 1;
    for(int i = 0 ; i <= N ; ++i)
        for(int j = 1 ; j <= N ; ++j){
            int k = read();
            if(i == 0)
                addEd(S , id(i + 1 , j) , k);
            else
                if(i == N)
                    addEd(id(i , j) , T , k);
                else
                    addEd(id(i , j) , id(i + 1 , j) , k);
        }
    for(int i = 1 ; i <= N ; ++i)
        for(int j = 0 ; j <= N ; ++j){
            int k = read();
            if(j == 0)
                addEd(id(i , j + 1) , T , k);
            else
                if(j == N)
                    addEd(S , id(i , j) , k);
                else
                    addEd(id(i , j + 1) , id(i , j) , k);
        }
    for(int i = 0 ; i <= N ; ++i)
        for(int j = 1 ; j <= N ; ++j){
            int k = read();
            if(i && i != N)
                addEd(id(i + 1 , j) , id(i , j) , k);
        }
    for(int i = 1 ; i <= N ; ++i)
        for(int j = 0 ; j <= N ; ++j){
            int k = read();
            if(j && j != N)
                addEd(id(i , j) , id(i , j + 1) , k);
        }
}

void work(){
    Dijk();
    cout << dis[T];
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in" , "r" , stdin);
    //freopen("out" , "w" , stdout);
#endif
    input();
    work();
    return 0;
}

posted @ 2019-01-29 10:25  cjoier_Itst  阅读(255)  评论(0编辑  收藏  举报