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\n",ans);
    return 0;
}

 

posted @ 2018-04-04 11:05  Star_Feel  阅读(204)  评论(0编辑  收藏  举报