BZOJ1001: [BeiJing2006]狼抓兔子 [最小割 | 对偶图+spfa]

1001: [BeiJing2006]狼抓兔子

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 19528  Solved: 4818
[Submit][Status][Discuss]

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) 
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击
这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.

Input

第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值. 
第二部分共N-1行,每行M个数,表示纵向道路的权值. 
第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 
输入文件保证不超过10M

Output

输出一个整数,表示参与伏击的狼的最小数量.

Sample Input

3 4
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6

Sample Output

14

HINT

 

 2015.4.16新加数据一组,可能会卡掉从前可以过的程序。


就是用狼把这个图割开
或者想最多兔子量,然后一个兔子一个狼
 
法1:dinic
注意这是无向图
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e6+5,INF=1e9;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,c,s,t;
struct edge{
    int v,ne,c,f;
}e[N*6];
int cnt,h[N];
inline void ins(int u,int v,int c){//printf("ins %d %d %d\n",u,v,c);
    cnt++;
    e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[v];h[v]=cnt;
}
inline int id(int i,int j){return (i-1)*m+j;}
int vis[N],d[N],q[N],head,tail;
inline void lop(int &x){if(x==N)x=1;}
bool bfs(){
    memset(vis,0,sizeof(vis));
    memset(d,0,sizeof(d));
    head=tail=1;
    q[tail++]=s;d[s]=0;vis[s]=1;
    while(head!=tail){
        int u=q[head++];lop(head);
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(!vis[v]&&e[i].c>e[i].f){
                vis[v]=1;d[v]=d[u]+1;
                q[tail++]=v;lop(tail);
                if(v==t) return true;
            }
        }
    }
    return false;
}
int cur[N];
int dfs(int u,int a){
    if(u==t||a==0) return a;
    int flow=0,f;
    for(int &i=cur[u];i;i=e[i].ne){
        int v=e[i].v;
        if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c-e[i].f)))>0){
            flow+=f;
            e[i].f+=f;
            e[((i-1)^1)+1].f-=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}
int dinic(){
    int flow=0;
    while(bfs()){
        for(int i=s;i<=t;i++) cur[i]=h[i];
        flow+=dfs(s,INF);//printf("dinic %d\n",flow);
    }
    return flow;
}
int main(){
    n=read();m=read();s=id(1,1);t=n*m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m-1;j++){c=read();ins(id(i,j),id(i,j+1),c);}
    for(int i=1;i<=n-1;i++)
        for(int j=1;j<=m;j++) {c=read();ins(id(i,j),id(i+1,j),c);}
    for(int i=1;i<=n-1;i++)
        for(int j=1;j<=m-1;j++){c=read();ins(id(i,j),id(i+1,j+1),c);}
    int ans=dinic();
    printf("%d",ans);
}
View Code
法2:对偶图+spfa

浅析最大最小定理在信息学竞赛中的应用

对于平面图,对偶图的最短路就是原图的最小割

直接想也容易理解,最短路就是把一些边割了

想的时候可以加一条s*到t*的INF的边把s*和t*面割开,但是程序不要加,否则暴增3000ms

1116ms,dinic用了1684ms

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2e6+5,INF=1e9;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,c,s,t;
struct edge{
    int v,ne,w;
}e[N*4];
int h[N],cnt=0;
inline void ins(int u,int v,int w){//printf("ins %d %d %d\n",u,v,w);
    cnt++;
    e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
}
inline void lop(int &x){if(x==N) x=1;else if(x==0) x=N-1;}
int d[N],q[N],head,tail;bool inq[N];
int spfa(){
    memset(d,127,sizeof(d));
    head=tail=1;
    q[tail++]=s;inq[s]=1;d[s]=0;
    while(head!=tail){
        int u=q[head++];inq[u]=0;lop(head);
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v,w=e[i].w;
            if(d[v]>d[u]+w){
                d[v]=d[u]+w;
                if(!inq[v]){
                    if(d[v]<d[q[head]]) head--,lop(head),q[head]=v;
                    else q[tail++]=v,lop(tail);
                    inq[v]=1;
                }
            }
        }
    }
    return d[t];
}
int main(){
    n=read();m=read();
    int col=2*(m-1),row=n-1;
    s=0;t=col*row+1;//ins(s,t,INF);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m-1;j++){
            c=read();
            if(i==1) ins(t,(j<<1),c);
            else if(i==n) ins((i-2)*col+(j<<1)-1,s,c);
            else ins((i-2)*col+(j<<1)-1,(i-1)*col+(j<<1),c);
        }
    
    for(int i=1;i<=n-1;i++)
        for(int j=1;j<=m;j++){
            c=read();
            if(j==1) ins(s,(i-1)*col+1,c);
            else if(j==m) ins((i-1)*col+(j<<1)-2,t,c);
            else ins((i-1)*col+(j<<1)-2,(i-1)*col+(j<<1)-1,c);
        }
        
    for(int i=1;i<=n-1;i++)
        for(int j=1;j<=m-1;j++){
            c=read();
            ins((i-1)*col+(j<<1)-1,(i-1)*col+(j<<1),c);
        }
    int ans=spfa();
    printf("%d",ans);
}

 

 

 
 
posted @ 2016-12-09 21:04  Candy?  阅读(648)  评论(0编辑  收藏  举报