codeforce_exercise_r12

本文探讨了一道关于任务调度的问题,其中涉及一个拥有两个CPU和一个GPU的机器。任务可以在不同硬件资源上运行,目标是最小化完成所有任务所需的时间。作者尝试使用动态规划(DP)解决,但只得到了部分分数。解题思路2采用了未知的方法得到满分。博客中还分享了对问题的思考和挑战,以及对解题难点的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

任务调度(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我也不知道错在什么地方。总之,也希望有大佬能提供一个思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值