任务调度(csp201403-5) :
问题描述
题目简述
有若干个任务需要在一台机器上运行。它们之间没有依赖关系,因此 可以被按照任意顺序执行。
该机器有两个 CPU 和一个 GPU。对于每个任务,你可以为它分配不 同的硬件资源:
1. 在单个 CPU 上运行。
2. 在两个 CPU 上同时运行。
3. 在单个 CPU 和 GPU 上同时运行。
4. 在两个 CPU 和 GPU 上同时运行。
一个任务开始执行以后,将会独占它所用到的所有硬件资源,不得中 断,直到执行结束为止。第 i 个任务用单个 CPU,两个 CPU,单个 CPU 加 GPU,两个 CPU 加 GPU 运行所消耗的时间分别为 ai,bi,ci 和 di。
现在需要你计算出至少需要花多少时间可以把所有给定的任务完成。
输入/输出格式
输入格式:
输入的第一行只有一个正整数 n(1 ≤ n ≤ 40), 是总共需要执行的任 务个数。
接下来的 n 行每行有四个正整数 ai, bi, ci, di(ai, bi, ci, di 均不超过 10), 以空格隔开。
输出格式:
输出只有一个整数,即完成给定的所有任务所需的最少时间。
样例
输入样例:
3
4 4 2 2
7 4 7 4
3 3 3 3
输出样例:
7
问题分析
解题思路1(10pts)
我做的时候的思路,就是dp。因为看起来数据规模比较小,大概是一个dp问题。我设定的状态是dp(i,j)代表做完前i个任务,且CPU做最后一个任务处于状态j时,所需的最小时间。之后由于1状态和3状态之间是可以并行的,因此,需要判断并行后是否可以处于目标状态。其他状态的时间就是任务时间+dp时间-二者并行时间的最小值,并行时间为两者之间并行时间的差的绝对值。最后的结果为max(dp(n,j))(j=1,2,3,4)。但是做出来只有10分,我个人也不清楚到底错在哪了,也许这个状态本身求出的结果就不是最优的。但是我是真的没想明白。另外我也找不到AC的代码,也没法看思路。
参考代码
#include <iostream>
#include <cstring>
using namespace std;
const int inf=10000015;
class node
{
public:
int time;
int bx;
bool operator < (const node& n) const
{
if(time!=n.time) return time<n.time;
else return bx>n.bx;
}
};
node task[50][5];
node dp[50][5]; //dp[i][j]是做完前i个任务,最后一个任务为CPU状态j时所需的最少时间
int n;
void init()
{
memset(task,0,sizeof(task));
for(int i=0;i<50;i++)
{
for(int j=0;j<=4;j++)
{
dp[i][j].time=inf;
dp[i][j].bx=-1;
}
}
}
int main()
{
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=4;j++)
{
int t;
scanf("%d",&t);
if(j==1||j==3)
{
task[i][j].time=t;
task[i][j].bx=t;
}
else
{
task[i][j].time=t;
task[i][j].bx=0;
}
}
}
for(int j=1;j<=4;j++)
{
dp[1][j]=task[1][j];
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<=4;j++)
{
for(int k=1;k<=4;k++)
{
if(j==1&&k==3||j==3&&k==1)
{
if(dp[i-1][j].bx>=task[i][k].bx)
{
node tp;
tp.time=dp[i-1][j].time+task[i][k].time-task[i][k].bx;
tp.bx=dp[i-1][j].bx-task[i][k].bx;
dp[i][j]=min(dp[i][j],tp);
}
if(task[i][j].bx>=dp[i-1][k].bx)
{
node tp;
tp.time=task[i][j].time+dp[i-1][k].time-dp[i-1][k].bx;
tp.bx=task[i][j].bx-dp[i-1][k].bx;
dp[i][j]=min(dp[i][j],tp);
}
}
else
{
node tp1;
tp1.time=dp[i-1][j].time+task[i][k].time-min(dp[i-1][j].bx,task[i][k].bx);
tp1.bx=max(dp[i-1][j].bx,task[i][k].bx)-min(dp[i-1][j].bx,task[i][k].bx);
dp[i][j]=min(dp[i][j],tp1);
node tp2;
tp2.time=task[i][j].time+dp[i-1][k].time-min(task[i][j].bx,dp[i-1][k].bx);
tp2.bx=max(task[i][j].bx,dp[i-1][k].bx)-min(task[i][j].bx,dp[i-1][k].bx);
dp[i][j]=min(dp[i][j],tp2);
}
}
}
}
node ans=dp[n][1];
for(int i=2;i<=4;i++)
{
ans=min(ans,dp[n][i]);
}
printf("%d",ans.time);
return 0;
}
解题思路2(30pts)
参考代码
#include<iostream>
#include<stack>
using namespace std;
int n,ans=2e9;
int f[410][410][410];
int cost[50][5];
int strategy[5][3]={{2,2,2},{1,0,0},{0,1,0},{3,0,3},{0,3,3}};
struct node{
int i,x,y,z;
};
stack<node> s;
void dfs(){
s.push({0,0,0,0});
f[0][0][0]=-1;
int i,x,y,z;
while(s.size()){
node temp=s.top();s.pop();
i=temp.i;
x=temp.x;
y=temp.y;
z=temp.z;
if(f[x][y][z]>=i) continue;
f[x][y][z]=i;
if(max(x,max(y,z))>ans) continue;
if(i==n){
ans=min(ans,max(x,max(y,z)));
continue;
}
i++;
for(int j=0;j<5;j++){
s.push({i,x+cost[i][strategy[j][0]],y+cost[i][strategy[j][1]],z+cost[i][strategy[j][2]]});
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=4;j++){
cin>>cost[i][j];
}
if(cost[i][2]>cost[i][4]) cost[i][2]=cost[i][4];
cost[i][0]=0;
}
dfs();
cout<<ans<<endl;
}
心得体会
好难的一道题,看上去挺简单,但是实际做起来却很麻烦。然后dp我也不知道错在什么地方。总之,也希望有大佬能提供一个思路。