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
  • 相关阅读:
    leetcode 347. Top K Frequent Elements
    581. Shortest Unsorted Continuous Subarray
    leetcode 3. Longest Substring Without Repeating Characters
    leetcode 217. Contains Duplicate、219. Contains Duplicate II、220. Contains Duplicate、287. Find the Duplicate Number 、442. Find All Duplicates in an Array 、448. Find All Numbers Disappeared in an Array
    leetcode 461. Hamming Distance
    leetcode 19. Remove Nth Node From End of List
    leetcode 100. Same Tree、101. Symmetric Tree
    leetcode 171. Excel Sheet Column Number
    leetcode 242. Valid Anagram
    leetcode 326. Power of Three
  • 原文地址:https://www.cnblogs.com/Narh/p/10165510.html
Copyright © 2011-2022 走看看