zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        return 0;
    }
    View Code

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

    学习了学长的不显式建图的方法。大概 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
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    python实用库:PrettyTable 学习
    centos启动错误:Inodes that were part of a corrupted orphan linked list found.
    C++:in namespace 'std' does not name a template type
    小程序实现单词查询搜索及搜索的历史记录
    小程序图片懒加载较完美解决方案
    下载文件到本地解压压缩包出现文件损坏,报错问题已解决
    彻底理解cookie,session,token
    vue全家桶(Vue+Vue-router+Vuex+axios)(Vue+webpack项目实战系列之二)
    与关系型数据库相比,MongoDB的优缺点
    漫谈JS 的继承方式
  • 原文地址:https://www.cnblogs.com/Narh/p/10165510.html
Copyright © 2011-2022 走看看