zoukankan      html  css  js  c++  java
  • BZOJ 1001 平面图与对偶图的转化 最短路Or最大流

    思路:
    1.按照题意求最小割 转换成最大流用Dinic解
    2. 转换成对偶图 求最短路
    Dinic:

    //By SiriusRen
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 1100000
    int n,m,first[N],next[N*6],v[N*6],w[N*6],tot,jy,ans,vis[N],S,T,xx,pos[N];
    void Add(int x,int y,int z){w[tot]=z,v[tot]=y,next[tot]=first[x],first[x]=tot++;}
    void add(int x,int y,int z){Add(x,y,z),Add(y,x,z);}
    bool tell(){
        memset(vis,-1,sizeof(vis)),vis[S]=0;
        queue<int>q;q.push(S);
        while(!q.empty()){
            int t=q.front();q.pop();
            for(int i=first[t];~i;i=next[i])
                if(w[i]&&vis[v[i]]==-1)
                    vis[v[i]]=vis[t]+1,q.push(v[i]);
        }return vis[T]!=-1;
    }
    int zeng(int x,int y){
        if(x==T)return y;
        int r=0;
        for(int i=first[x];~i&&y>r;i=next[i])
            if(w[i]&&vis[v[i]]==vis[x]+1){
                int t=zeng(v[i],min(y-r,w[i]));
                w[i]-=t,w[i^1]+=t,r+=t;
            }
        if(!r)vis[x]=-1;
        return r;
    }
    int main(){
        memset(first,-1,sizeof(first));
        scanf("%d%d",&n,&m);
        S=m+1,T=n*m+m;
        for(int i=1;i<=n;i++)for(int j=1;j<m;j++)
            scanf("%d",&xx),add(i*m+j,i*m+j+1,xx);
        for(int i=1;i<n;i++)for(int j=1;j<=m;j++)
            scanf("%d",&xx),add(i*m+j,(i+1)*m+j,xx);
        for(int i=1;i<n;i++)for(int j=1;j<m;j++)
            scanf("%d",&xx),add(i*m+j,(i+1)*m+j+1,xx);
        while(tell())while(jy=zeng(S,0x3fffffff))ans+=jy;
        printf("%d
    ",ans);
    }

    Dijkstra:
    这里写图片描述
    这么转成对偶图
    在原平面图中添加一条从起点S到终点T的边,会增加一个区域S’。
    无限大的区域设为T’。
    把加边后的平面图按照上面的方法转化为对偶图。
    删去边S’-T’。
    此时S-T的最小割大小等于S’到T’的最短路长度。

    Ps:需要特判n=1|m=1的情况

    //By SiriusRen
    #include <queue>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define M 1111*1111*6
    int n,m,a[1005][1005],b[1005][1005],c[1005][1005],T=2000*1005;
    int first[M/3],next[M],v[M],w[M],tot,vis[M/3],d[M/3];
    void Add(int x,int y,int z){w[tot]=z,v[tot]=y,next[tot]=first[x],first[x]=tot++;}
    struct Node{int now,weight;}jy;
    bool operator < (Node a,Node b){return a.weight>b.weight;}
    void Dijkstra(){
        priority_queue<Node>pq;pq.push(jy);
        while(!pq.empty()){
            Node t=pq.top();pq.pop();
            if(vis[t.now])continue;
            for(int i=first[t.now];~i;i=next[i])if(d[v[i]]>d[t.now]+w[i])
                d[v[i]]=d[t.now]+w[i],jy.now=v[i],jy.weight=d[v[i]],pq.push(jy);
        }printf("%d
    ",d[T]=0x3f3f3f3f?d[T]:0);
    }
    void add(int x,int y,int z){Add(x,y,z),Add(y,x,z);}
    int main(){
        memset(first,-1,sizeof(first)),memset(d,0x3f,sizeof(d)),d[0]=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)for(int j=1;j<m;j++)scanf("%d",&a[i][j]);
        for(int i=1;i<n;i++)for(int j=1;j<=m;j++)scanf("%d",&b[i][j]);
        for(int i=1;i<n;i++)for(int j=1;j<m;j++)scanf("%d",&c[i][j]);
        if(n==1||m==1){
            if(m==1)for(int i=1;i<n;i++)d[T]=min(d[T],b[i][1]);
            if(n==1)for(int i=1;i<m;i++)d[T]=min(d[T],a[1][i]);
        }
        for(int i=1;i<n;i++)for(int j=1;j<m;j++){
            int cnt=((i-1)*(m-1)+j)*2;
            add(cnt-1,cnt,c[i][j]);
            if(j!=m-1)add(cnt-1,cnt+2,b[i][j+1]);
            if(i!=n-1)add(cnt,cnt+(m-1)*2-1,a[i+1][j]);
        }
        for(int i=1;i<n;i++)add(((i-1)*(m-1)+1)*2,T,b[i][1]),add(0,2*i*(m-1)-1,b[i][m]);
        for(int i=1;i<m;i++)add(0,2*i-1,a[1][i]),add(2*((n-2)*(m-1)+i),T,a[n][i]);
        Dijkstra();
    }

    这里写图片描述
    效率竟然差不多?

  • 相关阅读:
    堆重启_uaf_hacknote
    记一次Spring表达式注入
    绕过waf的另类木马文件攻击方法
    西湖论剑 Flagshop 分析复现
    【测开基础之计算机网络】二: 物理层_网络_TesterAllen的博客CSDN博客
    测试面试 | 某 BAT 大厂测试开发面试真题与重点解析
    谁懂这篇文,玩游戏还会卡顿?
    移动自动化测试入门,你必须了解的背景知识和工具特性
    Python 自动化测试(三): pytest 参数化测试用例构建
    接口自动化测试分层设计与实践总结
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6532136.html
Copyright © 2011-2022 走看看