Working Plan 优先队列+贪心

题目链接:http://codeforces.com/gym/101987
题目描述
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
题意:有m个工人,要工作n天,每个工人可以连续工作w天,之后就要休息h天,给定每个工人的工作天数b[i],和每天需要的工人数a[i],问工人的数量能否满足每天的工作安排,若可以,输出1,并输出每个工人每次开始工作的日期(每个工人的工作次数为b[i]/w),若不能,直接输出-1.

 

题解:建立两个优先队列,工作队列Q和休息队列T,Q的优先级是工作次数,工作次数越多的越先进入工作队列,T的优先级是休息之后可以开始工作的时间,工作时间越早越先进入队列。工作队列的每个工人工作w天之后进入休息队列,休息队列里记录休息h天之后可以开始工作的日期,若这个日期小于当天日期,就可以进入工作队列

因为每个工人可以连续工作,在用一个vis数组记录每天需要新加入的工人数量

 

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int n, m, w, h;
int a[2005], b[2005], vis[2005];//vis记录每天需要新加入几个工人
vector<int>v[2005];
typedef struct node
{
    int num;//编号
    int cnt;//工作次数
    int time;//休息之后可以开始工作的日期
}node;

typedef struct cmp1//对队列T,可以开始工作的日期越早越先入队列
{
    bool operator () (const node &x, const node &y)
    {
        return x.time > y.time;
    }
}cmp1;
typedef struct cmp2//对队列Q,工作次数越多的越先进入队列
{
    bool operator () (const node &x, const node &y)
    {
        return x.cnt < y.cnt;
    }

}cmp2;
priority_queue<node, vector<node>, cmp2>Q;//工作队列
priority_queue<node, vector<node>, cmp1>T;//休息队列
int main()
{
    node p[2005];
    cin >> m >> n >> w >> h;
    for (int i = 1; i <= m; i++)
    {
        cin >> b[i];
        p[i].num = i;
        p[i].cnt = b[i] / w;
        p[i].time = 0;
        Q.push(p[i]);
    }
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    int flag = 1;
    for (int i = 1; i <= n; i++)
    {
        if(a[i]!=0)
        {
            int temp = a[i];
            vis[i] = a[i];
            for (int j = i; j <= i + w - 1; j++)//因为每个人都是连续工作的,之后的w天都要减去a[i]得到需要新加入的人数
                a[j] = a[j] - temp;
        }
    }
    node temp;
    for (int i = 1; i <= n; i++)
    {
        while (!T.empty())
        {
            temp = T.top();
            if (temp.time <= i)//如果可以开始工作的日期小于当前日期
            {
                Q.push(temp);
                T.pop();
            }
            else
                break;
        }
        while (!Q.empty() && vis[i])
        {
            temp = Q.top();
            Q.pop();
            vis[i]--;
            temp.time = i + w + h;
            temp.cnt--;
            v[temp.num].push_back(i);//记录每次开始工作的日期
                if (temp.cnt != 0)
                    T.push(temp);
        }
        if (vis[i] != 0)//人数不够
        {
            flag = 0;
            break;
        }
    }
    if (flag == 0)
        cout << -1 << endl;
    else
    {
        cout << 1 << endl;
        for (int i = 1; i <= m; i++)
        {
            for (int j = 0; j < v[i].size(); j++)
            {
                cout << v[i][j];
                if (j != v[i].size())
                    cout << ' ';
            }
            cout << endl;
        }
    }
    return 0;

}

 

posted @ 2019-05-05 10:32  知道了呀~  阅读(333)  评论(0编辑  收藏  举报