题目大意:
给m个人,和n天,然后再给一个人连续工作的天数w,和他工作w天之后要休息h天才能再次开始w天的工作。
给出m个人一共要工作的天数,和n天每天的工作天数,求是否有可行解。
说白了,就是给一个n*m的矩阵,然后起初全是0,往里边填1,对于每个人填1只能连着w个一起填,然后休息h天后才能再填。问是否有可行解。
题目思路:
首先这题需要SPJ,本题细节超多,先要处理出来每天有多少个人需要在这天开始工作也就是代码中的st数组(被样例迷惑就按2算了,无情WA test 1),然后每次安排人要优先安排当前需要工作天数最多的人,比如样例第一天需要安排1个人开始,那么这一天给3号。但是问题来了,怎么处理他h天之后再次开始工作。仔(糊)细(思)思(乱)考(想)之后很容易想到用两个队列一个工作队列一个休息队列。
(这很像CF div2 533的D题 传送门:https://blog.csdn.net/qq_41645482/article/details/88145658)。
队列元素是结构体类型,需要每个人的id号,每个人的当前去要工作天数cnt,还有这个人下次开始的工作时间next。
一个优先队列就是工作队列用来存当前可安排工作的需要天数最大的人,然后安排他这一天之后马上入下一个休息队列。
我们用一层循环遍历天数。然后立即查询休息队列中有没有可以回工作队列的也就是说结束休息可以再次开始工作。然后立即入工作队列。再查看当前工作天数是否有足够的人能安排工作,不能就安排不了。能够安排的话就取出工作队列的队首然后修改next和cnt,如果cnt!=0入休息队列。最后判断是否两个队列全空。vector存答案。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#define ll long long
using namespace std;
const ll MAXN=2005;
vector<int>v[MAXN];
int day[MAXN],per[MAXN],st[MAXN];
struct Point
{int id,cnt,next;Point(int i,int c,int n){id=i;cnt=c;next=n;}bool operator < (const Point& r)const{return cnt<r.cnt;}
};
int main()
{int m,n,w,h;priority_queue<Point>q;queue<Point>q1;cin>>m>>n>>w>>h;for(int i=1;i<=m;i++){cin>>day[i];}st[0]=0;for(int i=1;i<=n;i++){cin>>per[i];st[i]=per[i];}for(int i=1;i<=n;i++){for(int j=i+1;j<=i+w-1;j++){st[j]-=st[i];}}bool f=1;for(int i=1;i<=m;i++){q.push(Point(i,day[i],1));}for(int i=1;i<=n;i++){while(q1.size()&&q1.front().next==i){Point now=q1.front();q1.pop();q.push(now);}while(st[i]--){if(q.size()==0){f=0;break;}Point now=q.top();q.pop();if(i+w-1>n){f=0;break;}v[now.id].push_back(i);now.next=i+w+h;now.cnt-=w;if(now.cnt!=0)q1.push(now);}}if(q.size()||q1.size())f=0;if(f)cout<<1<<endl;else {cout<<-1<<endl;return 0;}for(int i=1;i<=m;i++){int len=v[i].size();for(int j=0;j<len;j++){printf("%d%c",v[i][j],(j==len-1)?'\n':' ');}}
}