bzoj 2007 [Noi2010]海拔——最小割转最短路

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2007

一个点的高度一定不是0就是1。答案一定形如一个左上角的连通块全是0的点、一个右下角的连通块全是1的点。

注意从东到西还有从南到北的边也有用!因为不一定是一个阶梯形的,还可以拐来拐去,只是一定是两个连通块罢了。

所以最小割一下那个分界线就行了。但会TLE。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=500*501+5,M=4000*501+5,INF=2e6+5;
int n,t,bh[505][505],hd[N],xnt=1,cur[N],to[M],nxt[M],cap[M];
int dfn[N],q[N],he,tl;
int Mn(int a,int b){return a<b?a:b;}
int rdn()
{
    int ret=0;bool fx=1;char ch=getchar();
    while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)fx=0;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘)ret=ret*10+ch-‘0‘,ch=getchar();
    return fx?ret:-ret;
}
void add(int x,int y,int z)
{
    to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=z;
    to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=0;
}
bool bfs()
{
    memset(dfn,0,sizeof dfn);dfn[0]=1;
    q[he=tl=1]=0;
    while(he<=tl)
    {
        int k=q[he++];
        for(int i=hd[k],v;i;i=nxt[i])
            if(cap[i]&&!dfn[v=to[i]])
                dfn[v]=dfn[k]+1,q[++tl]=v;
    }
    return dfn[t];
}
int dinic(int cr,int flow)
{
    if(cr==t)return flow;
    int use=0;
    for(int& i=cur[cr],v;i;i=nxt[i])
        if(cap[i]&&dfn[v=to[i]]==dfn[cr]+1)
        {
            int tmp=dinic(v,Mn(flow-use,cap[i]));
            if(!tmp)dfn[v]=0;
            use+=tmp;cap[i]-=tmp;cap[i^1]+=tmp;
            if(use==flow)return use;
        }
    return use;
}
int main()
{
    n=rdn();
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)bh[i][j]=t++;
    t--; int d;
    for(int i=0;i<=n;i++)
        for(int j=1;j<=n;j++)
            d=rdn(),add(bh[i][j-1],bh[i][j],d);
    for(int i=1;i<=n;i++)
        for(int j=0;j<=n;j++)
            d=rdn(),add(bh[i-1][j],bh[i][j],d);
    for(int i=0;i<=n;i++)
        for(int j=1;j<=n;j++)
            d=rdn(),add(bh[i][j],bh[i][j-1],d);
    for(int i=1;i<=n;i++)
        for(int j=0;j<=n;j++)
            d=rdn(),add(bh[i][j],bh[i-1][j],d);
    int ans=0;
    while(bfs())memcpy(cur,hd,sizeof hd),ans+=dinic(0,INF);
    printf("%d\n",ans);
    return 0;
}

可以转成最短路。注意边的方向。

学习了学长的不显式建图的方法。大概 dis[ ][ ] 记录的就是从起点走到格子的距离,再记4个 dis[ ][ ] 表示它的周围4条边的容量,之类的。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=505,INF=2e6+5;
int n,dis[5][N][N],ans=INF;bool vis[N][N];
struct Node{
    int x,y,dis;
    Node(int a=0,int b=0,int d=0):x(a),y(b),dis(d) {}
    bool operator< (const Node &b)const
    {return dis>b.dis;}
};
priority_queue<Node> q;
int Mn(int a,int b){return a<b?a:b;}
int rdn()
{
    int ret=0;bool fx=1;char ch=getchar();
    while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)fx=0;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘)ret=ret*10+ch-‘0‘,ch=getchar();
    return fx?ret:-ret;
}
void add(int x,int y,int d)
{
    if(d<dis[4][x][y])
        dis[4][x][y]=d,q.push(Node(x,y,d));
}
void dj()
{
    for(int i=1;i<=n;i++)add(1,i,dis[0][1][i]);
    for(int i=1;i<=n;i++)add(i,n,dis[1][i][n+1]);
    while(q.size())
    {
        int x=q.top().x,y=q.top().y,d=q.top().dis; q.pop();
        if(vis[x][y])continue; vis[x][y]=1;
        if(x<n)add(x+1,y,d+dis[0][x+1][y]);//x+1(up)
        if(y>1)add(x,y-1,d+dis[1][x][y]);
        if(x>1)add(x-1,y,d+dis[2][x-1][y]);//x-1(dn)
        if(y<n)add(x,y+1,d+dis[3][x][y]);
    }
    for(int i=1;i<=n;i++)ans=Mn(ans,dis[4][i][1]+dis[1][i][1]);
    for(int i=1;i<=n;i++)ans=Mn(ans,dis[4][n][i]+dis[0][n+1][i]);//n+1
}
int main()
{
    n=rdn();int d=n+1;
    for(int i=1;i<=d;i++)
        for(int j=1;j<=n;j++)dis[0][i][j]=rdn();//up
    for(int i=1;i<=n;i++)
        for(int j=1;j<=d;j++)dis[1][i][j]=rdn();//left
    for(int i=0;i<=n;i++)//0~n & 1~n !!!
        for(int j=1;j<=n;j++)dis[2][i][j]=rdn();//dn
    for(int i=1;i<=n;i++)
        for(int j=0;j<=n;j++)dis[3][i][j]=rdn();//right
    memset(dis[4],0x3f,sizeof dis[4]);
    dj();
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/10165510.html

时间: 2024-10-11 06:52:10

bzoj 2007 [Noi2010]海拔——最小割转最短路的相关文章

【bzoj2007】[Noi2010]海拔 最小割+对偶图+最短路

题目描述 YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路(简称道路),每条双向道路连接主干道上两个相邻的交叉路口.下图为一张YT市的地图(n = 2),城市被划分为2×2个区域,包括3×3个交叉路口和12条双向道路. 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期间YT市每条道路两个方向的人流量,即在高峰期间沿着

BZOJ 2007 NOI2010 海拔 平面图最小割

题目大意:YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路(简称道路),每条双向道路连接主干道上两个相邻的交叉路口.下图为一张YT市的地图(n = 2),城市被划分为2×2个区域,包括3×3个交叉路口和12条双向道路. 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期间YT市每条道路两个方向的人流量,即在高峰期间沿着

bzoj 2007: [Noi2010]海拔

1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #include<cstring> 5 #define pa pair<int,int> 6 #define M 250005 7 using namespace std; 8 int S,T,cnt=1,ans,head[M],next[10*M],u[10*M],v[10*M],d[M],f[M],n; 9 int p(in

2007: [Noi2010]海拔 - BZOJ

Description YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路(简称道路),每条双向道路连接主干道上两个相邻的交叉路口.下图为一张YT市的地图(n = 2),城市被划分为2×2个区域,包括3×3个交叉路口和12条双向道路. 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期间YT市每条道路两个方向的人流量,即

【BZOJ-2007】海拔 最小割 (平面图转对偶图 + 最短路)

2007: [Noi2010]海拔 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2095  Solved: 1002[Submit][Status][Discuss] Description YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路(简称道路),每条双向道路连接主

[bzoj1001][BeiJing2006]狼抓兔子-题解[平面图最小割转最短路]/[Dinic求最小割]

Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路

【BZOJ2007】【Noi2010】海拔 平面图最小割转最短路

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43280891"); } 题解:这个模型很水,不需要极角序神马转对偶图,直接乱搞就行. 然后目的是把图割开,那么只需要跑S->T最短路就行. 要做平面图转对偶图不妨去这篇. [BZOJ2965]保护古迹 平面图转对偶图,暴力,网络流 还有就是某人

bzoj 1497 最大获利 - 最小割

新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究.站址勘测.最优化等项目.在前期市场调查和站址勘测之后,公司得到了一共N个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为Pi(1≤i≤N).另外公司调查得出了所有期望中的

[BZOJ 2127] happiness 【最小割】

题目链接:BZOJ - 2127 题目分析 首先,每个人要么学文科,要么学理科,所以可以想到是一个最小割模型. 我们就确定一个人如果和 S 相连就是学文,如果和 T 相连就是学理. 那么我们再来确定建图.首先使用最小割,就是先加上所有可能获得的权值,再减去最小割(即不能获得的权值). 如果一个人学理,就要割掉与 S 相连的边,那么就是要割掉学文的收益.于是,对于每个点,从 S 向它连边,权值为它学文的收益. 同理,对于每个点,从它向 T 连边,权值为它学理的收益. 对于两个相邻的人,他们有同时学