BZOJ2007 [Noi2010]海拔(洛谷P2046)

平面图最小割->对偶图最短路

BZOJ题目传送门
洛谷题目传送门

最理想的情况当然是在某边道路上海拔从0变成1,而其它的海拔不变。这样总体力和就是这些边的权值和。

把权值看成容量的话就转变成一个最小割的问题。因为是平面图,可以转成对偶图的最短路来做。

顺便学了一发Dij+Heap。

其实挺套路的。主要建图很伤脑筋。我是右上为 S ,左下为 T

代码:

#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 505
#define M N*N
#define F inline
using namespace std;
struct edge{ int nxt,to,d; }ed[M<<2];
struct P{ int x,d; };
int n,m,k,s,t,h[M],d[M];
priority_queue <P> q;
F char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    return l==r?EOF:*l++;
}
F int _read(){
    int x=0; char ch=readc();
    while (!isdigit(ch)) ch=readc();
    while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
    return x;
}
#define addedge(x,y,z) ed[++k]=(edge){h[x],y,z},h[x]=k
F bool operator < (P a,P b){ return a.d>b.d; }
F int Dij(){
    for (int i=1;i<=t;i++) d[i]=0x7fffffff;
    q.push((P){s,0});
    while (!q.empty()){
        if (q.top().d>d[q.top().x]) { q.pop(); continue; } 
        int x=q.top().x; q.pop();
        for (int i=h[x],v;i;i=ed[i].nxt)
            if (d[x]+ed[i].d<d[v=ed[i].to])
                d[v]=d[x]+ed[i].d,q.push((P){v,d[v]});
    }
    return d[t];
}
int main(){
    n=_read(),t=n*n+1;
    for (int i=0;i<=n;i++)
        for (int j=1;j<=n;j++)
            addedge(max(s,(i-1)*n+j),min(t,i*n+j),_read());
    for (int i=1;i<=n;i++)
        for (int j=0;j<=n;j++)
            if (!j) addedge((i-1)*n+1,t,_read());
            else if (j==n) addedge(s,i*n,_read());
            else addedge((i-1)*n+j+1,(i-1)*n+j,_read());
    for (int i=0;i<=n;i++)
        for (int j=1;j<=n;j++)
            addedge(min(t,i*n+j),max(s,(i-1)*n+j),_read());
    for (int i=1;i<=n;i++)
        for (int j=0;j<=n;j++)
            if (!j) addedge(t,(i-1)*n+1,_read());
            else if (j==n) addedge(i*n,s,_read());
            else addedge((i-1)*n+j,(i-1)*n+j+1,_read());
    return printf("%d\n",Dij()),0;
}

猜你喜欢

转载自blog.csdn.net/a1799342217/article/details/80939501
今日推荐