【贪心+优先队列】Working Plan

题目链接:传送门

题目描述

ICPC manager plans a new project which is to be carried out for n days. In this project, m persons numbered from 1 to m are supposed to work. Each day j (1 ≤ j ≤ n) requires dj persons, and each person i (1 ≤ i ≤ m) wants to work wi days.

To increase the efficiency in performing the project, the following two conditions should be satisfied:
    1.each person works for only consecutive w days when he/she works, and
    2.each person can work again after he/she has a rest for at least h days.
ICPC manager wants to find a working plan to assign the working days for all persons such that the number of working days of each person i (1 ≤ i ≤ m) is equal to wi and the number of persons who work for each day j (1 ≤ j ≤ n) is equal to dj, and above two conditions are also satisfied.

For example, assume the project is carried out for n = 9 days, and m = 4 persons participate in the project. Let w = 2 and h = 1. Also, assume (w1, w2, w3, w4) = (4, 4, 6, 2) and (d1, d2, d3, d4, d5, d6, d7, d8, d9) = (1, 3, 2, 1, 2, 1, 1, 3, 2). The table below shows a feasible solution where the i-th row corresponds to person i, and the j-th column corresponds to day j. If person i works or has a rest in day j, the value of the table element with row i and column j is 1 or 0, respectively.

Given m, n, w, h, wi (1 ≤ i ≤ m) which is a multiple of w, and dj (1 ≤ j ≤ n), write a program to find a feasible solution as a working plan.


输入

Your program is to read from standard input. The input starts with a line containing four integers, m, n, w, h (1 ≤ m ≤ 2,000, 1 ≤ n ≤ 2,000, 1 ≤ w, h ≤ n). The following line contains m integers where the i-th (1 ≤ i ≤ m) integer represents wi (1 ≤ wi ≤ n) which is a multiple of w. The next line contains n integers where the j-th (1 ≤ j ≤ n) integer represents dj (0 ≤ dj ≤ m).


输出

Your program is to write to standard output. If there is a feasible working plan, print 1 in the first line followed by m lines, each i-th (1 ≤ i ≤ m) line should contain wi/w integers. These integers form an increasing sequence of first days that person i works in the feasible plan. If there is no feasible working plan, print only -1 in the first line. The first sample below corresponds to the example given in the table above.


样例输入

样例数据

4 9 2 1
4 4 6 2
1 3 2 1 2 1 1 3 2

样例输出

1
1 8
2 7
2 5 8
4

【题意】:

有n天,m个工人,他们一旦工作就要连续工作w天,然后需要休息h天。

然后每个工人需要工作wi天,其中这个wi天是需要能被w天整除的。

最后是n天,每一天需要的工人数目。


【题解】:

其实贪心的题目写博客真的没有什么意思,但是这个题目非常具有代表性,这个题目就是代表着我们的操作系统中,进程调度,这一个环节。贪心进行即可。

把所有需要的人数的天数单独处理,用vis[i],表示,即第i天需要的工人数,因为题目给的那些是工人数,但是实际上每个工人都是连续工作多少天的,我们可以预处理这个数组出来。

处理完了,我们就知道1~n天每一天真正需要的人数对吧。

然后我们需要设立两个优先队列,

一个优先队列叫做 就绪队列Q,就是里面都是空闲的工人。

另外的一个优先队列叫做:阻塞队列tQ,里面都是已经派出去工作的工人,但是他们需要到某一个时间回来。

这个就是完整的一个进程调度的过程,看吧!!!

我们就是贪心处理,我们让就绪队列Q,按照工人的需要工作的天数排序,工作天数越大的排前面。

相对地,阻塞队列tQ,就需要按照工人回来下一次工作的时间进行排序。

然后我们就可以写出这个代码了

 

#include <stdio.h>
#include <string.h>
#include <map>
#include <algorithm>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int N = 5e6+10;
const ll mod = 998244353;
const double eps = 1e-7;
int a[N],b[N],c[N],d[N],vis[N];

typedef struct Node{
    int No,val,t;
}Node;
typedef struct Cmp1{
    bool operator () (const Node &u,const Node &v)const {
        return u.t > v.t;
    }
}Cmp1;
typedef struct Cmp2{
    bool operator () (const Node &u,const Node &v)const {
        return u.val < v.val;
    }
}Cmp2;
Node w[N];
vector<int>v[2020];
int main()
{
    int n,m,h,W;
    scanf("%d%d%d%d",&m,&n,&W,&h);
    priority_queue <Node,vector<Node> ,Cmp2> Q;
    priority_queue <Node,vector<Node> ,Cmp1> tQ;
    for(int i=1;i<=m;i++){
        scanf("%d",&b[i]);
        w[i].No = i;
        w[i].val = b[i]/W;
        w[i].t = 0;
        Q.push(w[i]);
    }
    /*while(!Q.empty()){
        Node t = Q.top();
        Q.pop();
        printf("%d %d\n",t.No,t.val);
    }*/
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int cnt = 0 ,flag=1;
    for(int i=1;i<=n;i++){

        if(a[i]!=0){
            int t=a[i];
            for(int j=1;j<=a[i];j++){
                //vis[i]++;
                d[cnt++] = i;
            }
            vis[ i ]+=a[i];
            for(int j=i;j<=i+W-1;j++)
                a[j]-=t;
        }
    }
    /*
    for(int i=0;i<cnt;i++){
        printf("%d%c",d[i],i==cnt-1?'\n':' ');
    }
    for(int i=1;i<=n;i++){
        printf("%d%c",vis[i],i==n?'\n':' ');
    }*/
    Node cur;
    for(int i=1;i<=n;i++){
        while( !tQ.empty() ){
            cur = tQ.top();
            if ( cur.t <= i ){
                Q.push(cur);
                tQ.pop();
            }else{
                break;
            }
        }
        while( !Q.empty() && vis[i] ){
            cur = Q.top();
            Q.pop();
            vis[i]--;
            cur.t = i + W + h;
            cur.val -- ;
            v[cur.No].push_back(i);
            if(cur.val!=0)
                tQ.push(cur);
        }
        if(vis[i]){
            flag=0;break;
        }
    }
    if(!flag){
        printf("-1\n");
    }else{
        printf("1\n");
        for(int i=1;i<=m;i++){
            int sz = v[i].size();
            int cnt =0;
            for(auto j :v[i]){
                cnt++;
                printf("%d%c",j,cnt==sz?'\n':' ');
            }
        }
    }
    return 0;
}
/*
4 14 3 2
9 6 9 6
2 3 3 2 1 2 2 2 1 2 3 4 2 1
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值