飞扬的小鸟

来源:互联网 发布:中国税务报网络报检索 编辑:程序博客网 时间:2024/05/01 21:03

题目描述

Flappy Bird是一款风靡一时的休闲手机游戏。玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙。如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败。
现在小鸟们遇到了一个难题,他们遇到了一堵巨大的墙,墙上仅有m个洞供他们通过,由于小鸟们的体型不同且墙上洞的形状也不同,所以每种体型的鸟通过每个洞的时间都不同,鸟的体型共有n种,第i种体型的鸟通过第j个洞需要的时间记为T(i,j),且一个洞必须前一只鸟通过之后后一只鸟才能开始通过。
从时刻0开始,鸟开始通过,而每一只鸟的等待时间为从时刻0到自己已经通过洞的时间。现在知道了第i种体型的鸟有pi只,请求出使所有鸟都通过墙的最少的等待时间之和。

网络流

显然的思路,用网络流做。
对每个洞拆点,i.j表示第i个洞被通过这个洞的倒数第j只鸟通过。
然后连边跑费用流。
然而边数太多直接爆炸,怎么办?
注意到i.j没被流i.j+1就绝不可能被流。
因此动态加边,初始只连所有到x.1的。
目前连到x.y,流成功一次加上所有到x.y+1的边。
然后莫名很慢,所以这里本辣鸡加上了对只有一个洞的特判(面向数据编程)

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=100000+10,maxm=7000000+10,inf=1000000000;int h[maxn],d[maxn],now[maxn],go[maxm],dis[maxm],co[maxm],fx[maxm],next[maxm];int id[150][850],di[150*850+10][2],time[50][150],a[50],w[850];bool bz[maxn];int i,j,k,l,r,s,t,n,m,p,tot,top,ans,last;void add(int x,int y,int z,int c,int d){    go[++tot]=y;    dis[tot]=z;    co[tot]=c;    fx[tot]=tot+d;    next[tot]=h[x];    h[x]=tot;}int dfs(int x,int flow,int las,int cost){    if (x==t){        ans+=flow*cost;        last=las;        return flow;    }    bz[x]=1;    int r=now[x],k;    while (r){        if (!bz[go[r]]&&dis[r]&&d[x]==d[go[r]]+co[r]){            k=dfs(go[r],min(flow,dis[r]),x,cost+co[r]);            if (k){                dis[r]-=k;                dis[fx[r]]+=k;                now[x]=r;                return k;            }        }        r=next[r];    }    return now[x]=0;}bool change(){    int tmp=inf,i,r;    fo(i,s,t)        if (bz[i]){            r=h[i];            while (r){                if (!bz[go[r]]&&dis[r]&&d[go[r]]+co[r]-d[i]<tmp) tmp=d[go[r]]+co[r]-d[i];                r=next[r];            }        }    if (tmp==inf) return 0;    fo(i,s,t)        if (bz[i]) d[i]+=tmp;    return 1;}int read(){    int x=0;    char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9'){        x=x*10+ch-'0';        ch=getchar();    }    return x;}int main(){    n=read();m=read();    fo(i,1,n) a[i]=read(),p+=a[i];    fo(i,1,n)        fo(j,1,m)            time[i][j]=read();    if (m==1){        top=0;        fo(i,1,n)            fo(j,1,a[i]) w[++top]=time[i][1];        sort(w+1,w+p+1);        fo(i,1,p) ans+=w[i]*(p-i+1);        printf("%d\n",ans);        return 0;    }    s=1;t=p*m+n+2;    fo(i,1,n){        add(s,i+1,a[i],0,1);        add(i+1,s,0,0,-1);    }    top=n+1;    fo(i,1,m)        fo(j,1,p){            id[i][j]=++top;            di[top][0]=i;            di[top][1]=j;            if (j==1)                fo(k,1,n){                    add(k+1,id[i][j],1,time[k][i]*j,1);                    add(id[i][j],k+1,0,-time[k][i]*j,-1);                }            if (j<=p){                add(id[i][j],t,1,0,1);                add(t,id[i][j],0,0,-1);            }        }    do{        fo(i,s,t) now[i]=h[i];        fill(bz+s,bz+t+1,0);        while (dfs(s,inf,-1,0)){            r=id[di[last][0]][di[last][1]+1];            fo(i,1,n){                add(i+1,r,1,time[i][di[last][0]]*(di[last][1]+1),1);                add(r,i+1,0,-time[i][di[last][0]]*(di[last][1]+1),-1);            }            fill(bz+s,bz+t+1,0);        }    }while (change());    printf("%d\n",ans);}
0 0