bzoj 1001: [BeiJing2006]狼抓兔子

真不知道bzoj为什么要把这么难的题放第一题,就这道题弄得我好久都不敢刷bzoj。。

一道很明显的网络流题,最大流最小割定理

只不过用网络流是过不了的,因为数据范围过大

但由于这是一个平面图,于是可以另辟蹊径

详情请搜:周冬《两极相通——浅析最大—最小定理在信息学竞赛中的应用》

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1003;
const int M = 2000005;
const int inf = 0x3f3f3f3f;
int head[M];
struct node
{
    int to,next,val;
}g[M + M];
int m,n,nm,num;
int dis[M],que[M];
bool flag[M];
void add(int s,int e,int v)
{
    g[num].to = e;
    g[num].val = v;
    g[num].next = head[s];
    head[s] = num ++;
}
int nextint()
{
    int ret;
    char c;
    while((c = getchar()) > '9' || c < '0')
        ;
    ret = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        ret = ret * 10 + c - '0';
    return ret;
}
void build()
{
    scanf("%d",&m);
    nm = (n * m - m - n + 1)<<1;//there are nm nodes in new graph except s and t;
    int i,j,tmp;
    memset(head,-1,sizeof(head));
    num = 0;
   
    for(j = 1;j < m;j ++)//
    {
        scanf("%d",&tmp);
        add(j,nm + 1,tmp);
    }
    for(i = 1;i < n - 1;i ++)
    {
        for(j = 1;j < m;j ++)
        {
            scanf("%d",&tmp);
            add((i<<1)* (m - 1) + j,((i<<1) - 1) * (m - 1) + j,tmp);
        }
    }
    for(j = 1;j < m;j ++)
    {
        scanf("%d",&tmp);
        add(0,((n<<1)-3) * (m - 1) + j,tmp);
    }
   
    for(i = 0;i < n - 1;i ++)
    {
        for(j = 1;j <= m;j ++)
        {
            scanf("%d",&tmp);
            if(j == 1)
                add(0,(i<<1)*(m - 1) + m,tmp);
            else if(j == m)
                    add((i<<1|1)*(m - 1),nm + 1,tmp);
                else
                    add((i<<1)*(m  - 1) + j - 1,(i<<1)*(m - 1) + j + m - 1,tmp);
        }
    }
   
    for(i = 0;i < n - 1;i ++)
    {
        for(j = 1;j < m;j ++)
        {
            scanf("%d",&tmp);
            add((i<<1|1)*(m - 1) + j,(i<<1)*(m - 1) + j,tmp);
        }
    }
}
void SPFA()
{
    int i,front,rear;
    memset(flag,false,sizeof(flag));
    memset(dis,0x3f,sizeof(dis));
    front = rear = dis[0] = 0;
    que[rear ++] = 0;
    flag[0] = true;
    while(front != rear)
    {
        int u = que[front ++];
        flag[u] = false;
        if(front == M)
            front = 0;
        for(int i = head[u];~i;i = g[i].next)
        {
            int v = g[i].to;
            if(dis[v] > dis[u] + g[i].val)
            {
                dis[v] = dis[u] + g[i].val;
                if(flag[v] == false)
                {
                    flag[v] = true;
                    que[rear ++] = v;
                    if(rear == M)
                        rear = 0;
                }
            }
        }
    }
}
void solve()
{
    SPFA();
    printf("%d\n",dis[nm + 1]);
}
int main()
{
    while(scanf("%d",&n) != EOF)
    {
        build();
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值