codeforces 82D Cinema Cashier dp 队列

题意:在一个电影院安排座位,观众是组团来的,每个团的观众坐在同一行。买票时可以选位置,所以,先到的团队都会选最好的,输出每个团队的座位。其中有个还是f(x,y)=abs(x-mid)+(y-mid);是每个位置的好坏程度,即距离中心点的距离,越小位置越好

做法:用队列的手法求出每个团队在每一行,每一起点的价值和。然后对于座位上有人的点,加入到队列中,并且适时弹出队列。如果存在队列为空的时刻,那个区域就是符合题意的。具体看代码,双端队列还是不熟练啊。

#include <iostream>
#include <deque>
#include <cstdio>
#include <cstring>
#define LMT 102
#define eps 1e8
using namespace std;
bool gra[LMT][LMT];
int l,r1,r2,value,wid,mid;
deque<int>noq;
int vn;
int abs(int x)
{
    return x>0?x:-x;
}
void solve(int vv,int i,int rr1,int rr2)
{
    if(value>=vv)
    {
        value=vv;l=i;r1=rr1;r2=rr2;
    }
}
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    mid=(k+1)>>1;
    memset(gra,1,sizeof(gra));
    while(n--)
    {
        scanf("%d",&wid);
        value=eps;
        for(int i=k;i>=1;i--)
        {
            noq.clear();
            vn=0;
            if(k<wid)break;
            for(int j=k;j>k-wid;j--)
            {
                if(!gra[i][j])noq.push_back(j);
                vn+=abs(i-mid)+abs(j-mid);
            }
           if(noq.empty())solve(vn,i,k-wid+1,k);
            for(int j=k-wid;j>=1;j--)
            {
               while(!noq.empty()&&(*noq.begin())-wid>=j)noq.pop_front();
               if(!gra[i][j])noq.push_back(j);
               vn=vn-(abs(i-mid)+abs(j+wid-mid))+abs(i-mid)+abs(j-mid);
                    if(noq.empty())solve(vn,i,j,j+wid-1);
            }
        }
            if(value<eps)
            {
                printf("%d %d %d\n",l,r1,r2);
                for(int i=r1;i<=r2;i++)gra[l][i]=0;
            }
            else printf("-1\n");
    }
    return 0;
}


你可能感兴趣的:(codeforces 82D Cinema Cashier dp 队列)