zoukankan      html  css  js  c++  java
  • BZOJ1930: [Shoi2003]pacman 吃豆豆

    【传送门:BZOJ1930


    简要题意:

      给出n个豆子和它们的坐标,保证在原点的右上方,有两个PACMAN在原点的左下方,每个PACMAN只能往右或往上移动,每移动到一个豆子所在的位置,就会把豆子吃掉,求出两个PACMAN的路径不相交的情况下,总共能吃到最多豆子


    题解:

      费用流

      建边:

      st->S,T->ed流量都为2,费用都为2,这样子才能保证是两个PACMAN在吃

      S->i流量为1,费用为0,i->i+n流量为1,费用为1,i+n->ed流量为1,费用为0

      如果i能走到j,说明x[i]<=x[j]&&y[i]<=y[j],那么i+n->j流量为1,费用为0

      然后跑最大费用最大流

      然而T了,因为有很多多余的情况

      首先如果i能走到j,j能走到k的话,那么实际上是不用连i->k的

      但是如果单纯不连的话,会错,因为实际上j只能走一次,走完之后就不能从i走到k了(而实际上走了j,i依然能走到k)

      所以多建一条边i->i+n流量为1,费用为0,这样子就可以使得i成为一次中转站且不影响答案

      然后要把i+n->j流量变为2,因为有可能出现借道(也就是中转站)的情况

      注意要多路增广


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    struct node
    {
        int x,y,d,c,next,other;
    }a[2100000];int len,last[5100];
    void ins(int x,int y,int d,int c)
    {
        int k1=++len,k2=++len;
        a[k1].x=x;a[k1].y=y;a[k1].d=d;a[k1].c=c;
        a[k1].next=last[x];last[x]=k1;
        a[k2].x=y;a[k2].y=x;a[k2].d=-d;a[k2].c=0;
        a[k2].next=last[y];last[y]=k2;
        a[k1].other=k2;
        a[k2].other=k1;
    }
    int d[5100],list[5100],st,ed;
    int pre[5100],pos[5100];
    bool v[5100];
    bool spfa()
    {
        memset(d,-63,sizeof(d));d[st]=0;
        memset(v,false,sizeof(v));v[st]=true;
        list[1]=st;
        int head=1,tail=2;
        bool bk=false;
        while(head!=tail)
        {
            int x=list[head];
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(a[k].c>0&&d[y]<d[x]+a[k].d)
                {
                    pre[y]=k;
                    pos[y]=x;
                    d[y]=d[x]+a[k].d;
                    if(v[y]==false)
                    {
                        v[y]=true;
                        if(y==ed) bk=true;
                        list[tail++]=y;if(tail==ed+1) tail=1;
                    }
                }
            }
            v[x]=false;
            head++;if(head==ed+1) head=1;
        }
        return bk;
    }
    int ans;
    void Flow()
    {
        while(spfa())
        {
            int t=1<<31-1;
            for(int x=ed;x!=st;x=pos[x]) t=min(t,a[pre[x]].c);
            for(int x=ed;x!=st;x=pos[x])
            {
                a[pre[x]].c-=t;
                a[a[pre[x]].other].c+=t;
            }
            ans+=t*d[ed];
        }
    }
    struct zb
    {
        int x,y;
    }p[2100];
    bool cmp(zb n1,zb n2)
    {
        if(n1.x<n2.x) return true;
        if(n1.x>n2.x) return false;
        if(n1.y<n2.y) return true;
        if(n1.y<n2.y) return false;
        return false;
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
        int S=0,T=2*n+1;st=T+1;ed=st+1;
        len=0;memset(last,0,sizeof(last));
        ins(st,S,0,2);ins(T,ed,0,2);
        sort(p+1,p+n+1,cmp);
        for(int i=1;i<=n;i++)
        {
            ins(S,i,0,1);
            ins(i+n,T,0,1);
            ins(i,i+n,1,1);
            ins(i,i+n,0,1);
            int mmax=0;
            for(int j=i-1;j>=1;j--)
            {
                if(p[i].y>=p[j].y&&p[j].y>mmax)
                {
                    mmax=p[j].y;
                    ins(j+n,i,0,2);
                }
            }
        }
        ans=0;
        Flow();
        printf("%d
    ",ans);
        return 0;
    }

     

  • 相关阅读:
    机器学习(十七)— SVD奇异值分解
    机器学习(十五)— Apriori算法、FP Growth算法
    机器学习(十四)— kMeans算法
    深度学习—反卷积的理解
    【ECMAScript5】ECMAScript5中有关数组的常用方法
    【window】window10永久关闭更新
    【js】使用javascript 实现静态网页分页效果
    【vue】钩子函数生命周期
    【vue】vue中ref用法
    【vue-waring】element UI 由版本1.4.12 升级到element-ui@2.0.10
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8716144.html
Copyright © 2011-2022 走看看