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

    1930: [Shoi2003]pacman 吃豆豆

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 1969  Solved: 461
    [Submit][Status][Discuss]

    Description

    两个PACMAN吃豆豆。一开始的时候,PACMAN都在坐标原点的左下方,豆豆都在右上方。PACMAN走到豆豆处就会吃掉它。PACMAN行走的路线很奇怪,只能向右走或者向上走,他们行走的路线不可以相交。 请你帮这两个PACMAN计算一下,他们俩加起来最多能吃掉多少豆豆。

    Input

    第一行为一个整数N,表示豆豆的数目。 接下来 N 行,每行一对正整数,表示第i个豆豆的坐标。任意两个豆豆的坐标都不会重合。

    Output

    仅有一行包含一个整数,即两个PACMAN加起来最多能吃掉的豆豆数量

    Sample Input

    8

    8 1

    1 5

    5 7

    2 2

    7 8

    4 6

    3 3

    6 4

    Sample Output

    7

    HINT

     

    N < = 2000

    Source

     
    [Submit][Status][Discuss]

    题目大意:
      两个 PACMAN 吃豆豆。一开始的时候,PACMAN 都在坐标原点的左下方,豆豆都在右上方。

    PACMAN 走到豆豆处就会吃掉它。PACMAN 行走的路线很奇怪,只能向走或者向上走,他们行走的路线不可以相交。

    请你帮这两个 PACMAN 计算一下,他们俩加起来最多能吃掉多少豆豆。

    解析:
      每个点拆成两个,之间连一条流量为1,费用为1的边;
      如果从一个点出发可以到达另一个点,就将前一个点的出点连向后一个点的入点
      跑费用流。但是这样显然是会TLE的
      如果i能到j,j能到k,那么显然无需连i->k这条边 这是一个剪枝
      加了这个剪枝之后可能会WA 因此还要考虑一个点经过多次的情况
      即每个点从入点向出点再连一条流量为1,费用为0的边
      加了这个之后就能过了 剪枝不强 但是没有什么情况能把这个卡掉
      MS是可以证明复杂度是根号级别的

    //204 ms

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int N=4005;
    const int inf=0x3f3f3f3f;
    struct node{int x,y;}g[N];
    struct edge{int v,cap,cost,next;}e[N*1000];int tot=1,head[N];
    int n,m,ans,S,T,dis[N],Prev[N],flow[N],q[N*20];
    bool vis[N];
    bool cmp(const node &a,const node &b){
        if(a.x!=b.x) return a.x<b.x;
        return a.y<b.y;
    }
    void add(int x,int y,int z,int cost){
        e[++tot].v=y;e[tot].cap=z;e[tot].cost=cost;e[tot].next=head[x];head[x]=tot;
        e[++tot].v=x;e[tot].cap=0;e[tot].cost=-cost;e[tot].next=head[y];head[y]=tot;
    }
    bool spfa(){
        for(int i=S;i<=T;i++) vis[i]=0,dis[i]=-1;
        //int h=0,t=1; RE*32!!!
        //改:用下面的unsigned short或用循环队列 
        unsigned short h=0,t=1;q[t]=S;dis[S]=0;flow[S]=inf;
        while(h!=t){
            int x=q[++h];vis[x]=0;
            for(int i=head[x];i;i=e[i].next){
                if(e[i].cap&&dis[e[i].v]<dis[x]+e[i].cost){
                    dis[e[i].v]=dis[x]+e[i].cost;
                    Prev[e[i].v]=i;
                    flow[e[i].v]=min(flow[x],e[i].cap);
                    if(!vis[e[i].v]){
                        vis[e[i].v]=1;
                        if(dis[e[i].v]>dis[x])
                            q[h--]=e[i].v;
                        else
                            q[++t]=e[i].v;
                    }
                }
            }
        }
        return dis[T]!=-1;
    }
    void augment(){
        for(int i=T;i!=S;i=e[Prev[i]^1].v){
            e[Prev[i]].cap-=flow[T];
            e[Prev[i]^1].cap+=flow[T];
        }
        ans+=dis[T]*flow[T];
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++) g[i].x=read(),g[i].y=read();
        sort(g+1,g+n+1,cmp);
        int sink=n<<1|1,sour=sink+1;S=0;T=sour+1;
        for(int i=1;i<=n;i++){
            add(sink,i,1,0);
            add(i,i+n,1,0);
            add(i,i+n,1,1);
            add(i+n,sour,1,0);
        }
        for(int i=1;i<=n;i++){
            int tmp=-1;
            for(int j=i-1;j;j--){
                if(g[j].y<=g[i].y&&g[j].y>tmp){
                    tmp=g[j].y;
                    add(j+n,i,2,0);
                }
            }
        }
        add(S,sink,2,0);
        add(sour,T,2,0);
        while(spfa()) augment();
        printf("%d",ans);
        return 0;
    }

    //=================================================================

    dp:

    首先建出图,f[i][j]表示a吃到了i点,b吃到了j点的最大值,转移的时候转移拓扑序小的那一维,如果i拓扑序小于j,那么转移到f[k][j],否则转移到f[i][k],建出的图边数也要优化,不然会超时。优化的方法是假如i,j连边,那么如果有一条边(i,k),x[k]>x[j]并且y[k]>y[j]那么(i,k)这条边就没有必要存在了。因为先取(i,j)在去(j,k)会比直接取(i,k)要好。

    //612 ms

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=10005;
    const int M=2005;
    struct node{int x,y;}g[N];
    struct edge{int v,next;}e[N*300];int tot,head[N];
    int n,cnt,T,rd[N],id[N],ID[N],q[N*2];
    int f[M][M];
    inline void add(int x,int y){
        e[++tot].v=y;e[tot].next=head[x];head[x]=tot;
        e[++tot].v=x;e[tot].next=head[y];head[y]=tot;
    }
    inline bool cmp(const node &a,const node &b){
        if(a.x!=b.x) return a.x<b.x;
        return a.y<b.y;
    }
    inline void top_sort(){
        unsigned short h=0,t=1;q[t]=0;
        while(h!=t){
            int x=q[++h];
            id[x]=++cnt;
            ID[cnt]=x;
            for(int i=head[x];i;i=e[i].next){
                if(--rd[e[i].v]==0){
                    q[++t]=e[i].v;
                }
            }
        }
    }
    inline void dp(int x,int y){
        for(int i=head[x];i;i=e[i].next){
            int a=e[i].v,b=y;
            if(id[a]>id[b]) swap(a,b);
            if(a!=b)
                f[a][b]=max(f[a][b],f[x][y]+1);
            else
                f[a][b]=max(f[a][b],f[x][y]);
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d",&g[i].x,&g[i].y);
        sort(g+1,g+n+1,cmp);
        for(int i=1;i<=n;i++){
            int tmp=2e9;
            for(int j=i+1;j<=n;j++){
                if(i!=j&&g[i].x<=g[j].x&&g[i].y<=g[j].y&&g[j].y<tmp){
                    tmp=g[j].y;
                    rd[j]++;
                    add(i,j);
                }
            }
        }
        T=n+1;
        for(int i=1;i<=n;i++){
            add(0,i);rd[i]++;
            add(i,T);rd[T]++;
        }
        top_sort();
        for(int i=1;i<=cnt;i++){
            for(int j=i;j<=cnt;j++){
                dp(ID[i],ID[j]);
            }
        }
        printf("%d",f[T][T]-1);
        return 0;
    }
  • 相关阅读:
    c盘清理
    Uploading source images to prepare for transformations HTTP Error 400: POST https://res.ionic.io/api/v1/upload
    maven install 与install:install 的区别
    mysql 、pgsql、oracle 常见分页
    Java 动态代理的原理
    浅谈EC和多副本
    工信部ICP备案后,是否还需要公安备案
    RHEL6.5、RHEL7.2忘记ROOT密码恢复小结
    域名恶意解析的原因是什么
    HTTP 请求头中的 X-Forwarded-For
  • 原文地址:https://www.cnblogs.com/shenben/p/6378906.html
Copyright © 2011-2022 走看看