题意:在一个电影院安排座位,观众是组团来的,每个团的观众坐在同一行。买票时可以选位置,所以,先到的团队都会选最好的,输出每个团队的座位。其中有个还是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; }