http://acm.hdu.edu.cn/showproblem.php?pid=2474
题意:有n个资源和m个进程,先给出一个n*m的资源分配表,再给出一个n*m的资源需求表,request[i][j]表示第j个进程还需要i中资源request[i][j]个。最后给出一个m数的序列,available[i]表示第i种资源可用的数目。问是否存在一个合适的进程序列使得n个进程都能执行完毕。
思路:比赛时先是纯模拟了一遍,傻X了,n<=50000。然后队友提示说弄两个队列,在当前队列里遍历进程,若当前进程可以执行就标记,否则就近进一个队列等待判断。结果TLE。
可以这么想,因为m<=3,可以将m种资源分别放在m个队列中,开始将n个进程每种资源的request放进对应优先队列中。一个进程要执行成功,要有m种资源,即该进程要出队m次,每出队一次,说明该资源可供当前进程使用。所以只需判断进程是否出队m次即可。
#include <iostream>
#include <string>
#include <cmath>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stack>
#include <vector>
#include <string.h>
#include <stdio.h>
using namespace std;
struct node
{
int id;
int need;
bool operator < (struct node tmp)const
{
return need < tmp.need;
}
}que[4][50010];
int n,m;
int allo[4][50010];
int ava[4];
int outque[50010];//记录每个进程出队列的次数
int p[4];
bool solve()
{
int flag = 1;
int i,j,k;
int sum = 0;
while(flag == 1)
{
flag = 0;
for(i = 1; i <= m; i++) //从第一个队列开始枚举
{
for( ; p[i] <= n; p[i]++)
{
if(ava[i] < que[i][p[i]].need)
break;
flag = 1;
outque[ que[i][p[i]].id ]++;
if(outque[ que[i][p[i]].id ] == m) //当出队次数等于m时,说明该进程可以执行
{
sum++;
for(j = 1; j <= m; j++) //更新vav[]。
ava[j] += allo[j][ que[i][p[i]].id ];
}
}
}
}
if(sum == n)
return true;
return false;
}
void debug()
{
for(int i = 1; i <= m; i++)
{
for(int j = 1; j <= n; j++)
printf("i :%d need: %d ",que[i][j].id,que[i][j].need);
printf("\n");
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
scanf("%d",&allo[i][j]);
for(int i = 1; i <= m; i++)
{
for(int j = 1; j <= n; j++)
{
que[i][j].id = j;
scanf("%d",&que[i][j].need); //先把每个进程对应的m个资源放进队列
}
}
//debug();
for(int i = 1; i <= m; i++)
{
scanf("%d",&ava[i]);
p[i] = 1;
sort(que[i]+1,que[i]+1+n); //对每种资源按需求量升序排序
}
//debug();
memset(outque,0,sizeof(outque));
if(solve())
printf("Yes\n");
else printf("No\n");
}
return 0;
}