zoukankan      html  css  js  c++  java
  • [BJOI2006]狼抓兔子

    题目:BZOJ1001、洛谷P4001。

    题目大意:在一张n×m的网格图中,每个格子都与其右、下、右下方各连有一条带权无向边。现在要你割去一些边,使得左上角的点无法到达右下角的点。并且要割掉的边的总权值最小。问最小是多少。

    解题思路:题意是求最小割,根据最小割等于最大流的定理,转化为最大流即可。

    由于无向图,建反向边时容量和正向边一样。

    但本题裸的dinic是过不了的,需要加一个优化:如果沿一条边走,发现返回值为0,则说明这条边已经无任何贡献了,在本次增广中不需要再考虑这条边(代码第54行)。

    然后优化一下常数就可以卡过去了。

    C++ Code:

    #include<stdio.h>
    #include<cctype>
    #include<cstring>
    #define N 1000002
    #define INF 0x3f3f3f3f
    int n,m,level[N],iter[N],head[N],cnt=0;
    struct edge{
        int to,cap,rev,nxt;
    }e[N*7];
    int q[5000005];
    inline int min(int a,int b){return a<b?a:b;}
    inline int readint(){
    	char c=getchar();
        int p=0;
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);c=getchar())
        p=p*10+c-'0';
        return p;
    }
    inline void addedge(int from,int to,int cap){
    	++cnt;
    	e[cnt]=(edge){to,cap,cnt+1,head[from]};
    	head[from]=cnt;
    	++cnt;
    	e[cnt]=(edge){from,cap,cnt-1,head[to]};
    	head[to]=cnt;
    }
    void bfs(int s){
        memset(level,-1,sizeof(level));
        level[s]=0;
        int l=0,r=1;
        q[1]=s;
        while(l!=r){
            int u=q[l=l%5000000+1];
            for(int i=head[u];i;i=e[i].nxt){
                int v=e[i].to;
                if(level[v]<0&&e[i].cap>0){
                    level[v]=level[u]+1;
                    q[r=r%5000000+1]=v;
                }
            }
        }
    }
    int dfs(int u,int t,int f){
        if(u==t)return f;
        for(int& i=iter[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(e[i].cap>0&&level[v]>level[u]){
                int d=dfs(v,t,min(f,e[i].cap));
                if(d){
                    e[i].cap-=d;
                    e[e[i].rev].cap+=d;
                    return d;
                }else level[v]=-1;
            }
        }
        return 0;
    }
    int max_flow(int s,int t){
        int flow=0;
        while(1){
            bfs(s);
            if(level[t]<0)return flow;
            memcpy(iter,head,sizeof(iter));
            int f;
            while(f=dfs(s,t,INF))flow+=f;
        }
    }
    int main(){
        n=readint(),m=readint();
        for(int i=1;i<=n;++i)
        for(int j=1;j<m;++j){
            int t=readint();
            addedge((i-1)*m+j,(i-1)*m+j+1,t);
        }
        for(int i=1;i<n;++i)
        for(int j=1;j<=m;++j){
            int t=readint();
            addedge((i-1)*m+j,i*m+j,t);
        }
        for(int i=1;i<n;++i)
        for(int j=1;j<m;++j){
            int t=readint();
            addedge((i-1)*m+j,i*m+j+1,t);
        }
        printf("%d
    ",max_flow(1,n*m));
        return 0;
    }
  • 相关阅读:
    2020软件工程作业05
    一、uart&tty驱动
    柔性数组使用备忘
    指针和数组备忘
    计算信息帧的校验和(备忘)
    Linux系统vim几个常见配置
    C语言实现过滤ASCII在0~127范围内的字符,并去除重复的字符
    extern "C"的用法
    strtol详解
    将一个十进制整数转换为二进制并输出
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/8067700.html
Copyright © 2011-2022 走看看