【BZOJ 1001:[BeiJing2006]狼抓兔子 最小割转对偶图堆优化dij

来源:互联网 发布:ros系统 与 linux 编辑:程序博客网 时间:2024/06/08 00:43

1001: [BeiJing2006]狼抓兔子

Time Limit: 15 Sec Memory Limit: 162 MB
Submit: 23509 Solved: 5914
[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

思路:首先第一感是裸的最大流,但数据范围很明显不允许这么做,这样只能过部分的点。
那么考虑其他做法,发现这个网格图实际上是一个对偶图,我们要求最大流也就是求最小割,那么最小割也可以看成一个割掉边的边,那么就可以看成连接一条边两侧的一条边。设置一个超级汇点和超级源点,跑一边spfa或者堆优化dij即可,注意堆优化dij别打残。

参考[知识点]网络流之转换对偶图
及参考2006年集训队论文 《浅析最大最小定理在信息学竞赛中的应用》周冬

部分分最大流做法:

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#define inf 1e9#define MAXN 10005using namespace std;queue<int> q;struct node{    int to,remain,next;}e[MAXN];int e_num=-1,point[MAXN];int deep[MAXN],cur[MAXN];bool vis[MAXN];int s,t,ans,n,m;void add(int from,int to,int remain){    ++e_num;    e[e_num].to=to;    e[e_num].remain=remain;    e[e_num].next=point[from];    point[from]=e_num;}bool bfs(int from,int to){    memset(deep,0x7f,sizeof(deep));    memset(vis,0,sizeof(vis));    for (int i=1;i<=n*m+1;i++)        cur[i]=point[i];    deep[from]=0;    vis[from]=1;    q.push(from);    while (!q.empty())    {        int u=q.front();        q.pop();        vis[u]=false;        for (int i=point[u];i!=-1;i=e[i].next)            if (deep[e[i].to]>inf&&e[i].remain)            {                deep[e[i].to]=deep[u]+1;                if (!vis[e[i].to])                {                    q.push(e[i].to);                    vis[e[i].to]=true;                }            }    }    return deep[to]<inf;} int dfs(int from,int to,int limit){    int f,flow=0;    if (!limit) return 0;    if (from==to) return limit;    for (int i=cur[from];i!=-1;i=e[i].next)    {        cur[from]=i;        if (deep[e[i].to]==deep[from]+1&&(f=dfs(e[i].to,to,min(limit,e[i].remain))))        {            flow+=f;            limit-=f;            e[i].remain-=f;            e[i^1].remain+=f;            if (!limit) break;        }    }    return flow;}void dinic(){    while (bfs(s,t))        ans+=dfs(s,t,inf);}int main(){    freopen("bjrabbit.in","r",stdin);    freopen("bjrabbit.out","w",stdout);    int x;    memset(point,-1,sizeof(point));    scanf("%d%d",&n,&m);    s=1;t=n*m;    for (int i=1;i<=n;i++)        for (int j=1;j<=m-1;j++)        {            scanf("%d",&x);            add((i-1)*m+j,(i-1)*m+j+1,x);            add((i-1)*m+j+1,(i-1)*m+j,0);            add((i-1)*m+j+1,(i-1)*m+j,x);            add((i-1)*m+j,(i-1)*m+j+1,0);        }    for (int i=1;i<=n-1;i++)        for (int j=1;j<=m;j++)        {            scanf("%d",&x);            add((i-1)*m+j,i*m+j,x);            add(i*m+j,(i-1)*m+j,0);            add(i*m+j,(i-1)*m+j,x);            add((i-1)*m+j,i*m+j,0);        }    for (int i=1;i<=n-1;i++)        for (int j=1;j<=m-1;j++)        {            scanf("%d",&x);            add((i-1)*m+j,i*m+j+1,x);            add(i*m+j+1,(i-1)*m+j,0);            add(i*m+j+1,(i-1)*m+j,x);            add((i-1)*m+j,i*m+j+1,0);        }    dinic();    printf("%d",ans);} 

满分对偶图做法:

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#define inf 1e9#define MAXN 2000005using namespace std;struct bian{    int to,dis,next;}e[MAXN];struct node{    int dis,id;    friend bool operator < (node a,node b)    {        return a.dis > b.dis;    }};int point[MAXN],e_num,cc[MAXN+100];int s,t,n,m;bool flag[MAXN];inline void add(int from,int to,int dis){    e_num++;    e[e_num].to=to;    e[e_num].dis=dis;    e[e_num].next=point[from];    point[from]=e_num;}void dij(){    for (int i=0;i<=MAXN;i++)        cc[i]=inf;    memset(flag,false,sizeof(flag));    cc[s]=0;    priority_queue<node> q;    node now;    now.id=s,now.dis=0;    q.push(now);    while (!q.empty())    {        now=q.top();        q.pop();        if (flag[now.id]==true) continue;        flag[now.id]=true;        int x=now.id;        for (int i=point[x];i;i=e[i].next)        {            if (cc[x]+e[i].dis<cc[e[i].to])            {                cc[e[i].to]=cc[x]+e[i].dis;                now.id=e[i].to;                now.dis=cc[e[i].to];                q.push(now);            }        }    }}int main(){    freopen("bjrabbit.in","r",stdin);    freopen("bjrabbit.out","w",stdout);    int x;    scanf("%d%d",&n,&m);    s=0;t=(n-1)*(m-1)+10;    for (int i=1;i<=n;i++)        for (int j=1;j<=m-1;j++)        {            scanf("%d",&x);            if (i==1) add(s,j,x),add(j,s,x);            else if (i==n) add((i*2-3)*(m-1)+j,t,x),add(t,(i*2-3)*(m-1)+j,x);            else             {                add(((i-1)*2-1)*(m-1)+j,((i-1)*2-1)*(m-1)+j+(m-1),x);                add(((i-1)*2-1)*(m-1)+j+(m-1),((i-1)*2-1)*(m-1)+j,x);            }        }    for (int i=1;i<=n-1;i++)        for (int j=1;j<=m;j++)        {            scanf("%d",&x);            if (j==1) add(t,(i*2-1)*(m-1)+j,x),add((i*2-1)*(m-1)+j,t,x);            else if (j==m) add(s,(i*2-1)*(m-1),x),add((i*2-1)*(m-1),s,x);            else            {                add((i-1)*2*(m-1)+j-1,(i-1)*2*(m-1)+j-1+m,x);                 add((i-1)*2*(m-1)+j-1+m,(i-1)*2*(m-1)+j-1,x);             }        }    for (int i=1;i<=n-1;i++)        for (int j=1;j<=m-1;j++)        {            scanf("%d",&x);            add((i-1)*2*(m-1)+j,(i-1)*2*(m-1)+j+(m-1),x);            add((i-1)*2*(m-1)+j+(m-1),(i-1)*2*(m-1)+j,x);        }    dij();    printf("%d",cc[t]);}
阅读全文
0 0
原创粉丝点击