bzoj 5403: marshland

题意

自己看

题解

这题还想了一会
主要是一开始想错方向了
一开始想的是把每一个有东西的点拆成4个
然后只需要把这么连
st>x1,x>x1,x2,x3,x4 s t − − > x 流 量 为 1 , x − − > x 1 , x 2 , x 3 , x 4
就可以解决只用一次了
但是剩下有一个问题,就是某些点用了某些点一定不能用
然后这个模型想了很久想不出来
这个方法明显的有问题
那就是没有用到,他按奇偶分点的特殊限制
于是我们考虑从这个条件入手
显然的,可能一起用的是可以黑白染色的
想到这个之后题解就出来了
就是白点拆成两排,然后中间是黑点
然后黑点每一个拆点,就可以了
具体自己想想把,提示到这里应该很明显了
实在不行自己看代码
因为以为地图是n*m的,于是RE了半个小时,我是SB
CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
typedef long long LL;
const LL MAX=(1<<30);
const LL N=55*55*2;
LL tx[4]={-1,0,0,1};
LL ty[4]={0,-1,1,0};
LL n,m,k;
LL a[55][55];
bool ok[55][55];//这个格子可不可以
struct qq
{
    LL x,y,last,z,z1;//费用 流量 
}e[N*500];LL num,last[N];
void init (LL x,LL y,LL z,LL z1)
{
    e[++num].x=x;e[num].y=y;e[num].z=z;e[num].z1=z1;
    e[num].last=last[x];
    last[x]=num;
    swap(x,y);z=0;z1=-z1;
    e[++num].x=x;e[num].y=y;e[num].z=z;e[num].z1=z1;
    e[num].last=last[x];
    last[x]=num;
}
LL P (LL x,LL y){return (x-1)*n+y;}
LL st,st1,ed;
bool check (LL x,LL y)
{
    if (x>=1&&y>=1&&x<=n&&y<=n&&ok[x][y]) return true;
    return false;
}
void bt ()
{
    for (LL u=1;u<=n;u+=2)
        for (LL i=1;i<=n;i+=2)
        {
            if (ok[u][i]==false) continue;
            LL id=P(u,i);
            init(st1,id,1,0);
            for (LL j=0;j<4;j++)
            {
                LL x=u+tx[j],y=i+ty[j];
                if (check(x,y)) init(id,P(x,y),1,0);
            }
        }
    for (LL u=2;u<=n;u+=2)
        for (LL i=2;i<=n;i+=2)
        {
            if (ok[u][i]==false) continue;
            LL id=P(u,i);
            init(id,ed,1,0);
            for (LL j=0;j<4;j++)
            {
                LL x=u+tx[j],y=i+ty[j];
                if (check(x,y)) init(P(x,y)+n*n,id,1,0);
            }
        }
    for (LL u=1;u<=n;u++)
        for (LL i=1;i<=n;i++)
            if ((u+i)%2!=0&&check(u,i))
                init(P(u,i),P(u,i)+n*n,1,a[u][i]);
}
LL from[N];
LL f[N];
bool in[N];
bool SPFA ()
{
    memset(in,false,sizeof(in));
    memset(from,-1,sizeof(from));
    for (LL u=1;u<=ed;u++) f[u]=-MAX;
    queue<LL> q;
    q.push(st);
    f[st]=0;in[st]=true;
    while (!q.empty())
    {
        LL x=q.front();q.pop();
        for (LL u=last[x];u!=-1;u=e[u].last)
        {
            LL y=e[u].y;
            if (e[u].z>0&&f[y]<f[x]+e[u].z1)
            {
                f[y]=f[x]+e[u].z1;from[y]=u;
                if (in[y]==false)
                {
                    in[y]=true;
                    q.push(y);
                }
            }
        }
        in[x]=false;
    }
    return f[ed]>0;
}
LL ans=0;
void lalal ()
{
    LL x=from[ed],t=MAX;
    while (x!=-1)
    {
        t=min(t,e[x].z);
        x=from[e[x].x];
    }
    x=from[ed];
    while (x!=-1)
    {
        ans=ans+t*e[x].z1;
        e[x].z-=t;
        e[x^1].z+=t;
        x=from[e[x].x];
    }
    return ;
}
int main()
{
    //freopen("a.in","r",stdin);
    num=1;memset(last,-1,sizeof(last));
    memset(ok,true,sizeof(ok));
    scanf("%lld%lld%lld",&n,&m,&k);
    st=n*n*2+1;st1=st+1;ed=st1+1;
    init(st,st1,m,0);
    LL sum=0;
    for (LL u=1;u<=n;u++)
        for (LL i=1;i<=n;i++)
        {
            scanf("%lld",&a[u][i]);
            sum=sum+a[u][i];
        }
    for (LL u=1;u<=k;u++)
    {
        LL x,y;
        scanf("%lld%lld",&x,&y);
        ok[x][y]=false;
    }
    bt();
    //printf("YES\n");
    while (SPFA()) lalal();
    printf("%lld\n",sum-ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值