• 【WC2001】【cogs358】高性能计算机(动态规划)


    【WC2001】【cogs358】高性能计算机(动态规划)

    ##题面
    

    【问题描述】

    现在有一项时间紧迫的工程计算任务要交给你——国家高性能并行计算机的主管工程师——来完成。为了尽可能充分发挥并行计算机的优势,我们的计算任务应当划分成若干个小的子任务。

    这项大型计算任务包括A和B两个互不相关的较小的计算任务。为了充分发挥并行计算机的运算能力,这些任务需要进行分解。研究发现,A和B都可以各自划分成很多较小的子任务,所有的A类子任务的工作量都是一样的,所有的B类子任务也是如此(A和B类的子任务的工作量不一定相同)。A和B两个计算任务之间,以及各子任务之间都没有执行顺序上的要求。

    这台超级计算机拥有p个计算节点,每个节点都包括一个串行处理器、本地主存和高速cache。然而由于常年使用和不连贯的升级,各个计算节点的计算能力并不对称。一个节点的计算能力包括如下几个方面:

    1. 就本任务来说,每个节点都有三种工作状态:待机、A类和B类。其中,A类状态下执行A类任务;B类状态下执行B类任务;待机状态下不执行计算。所有的处理器在开始工作之前都处于待机状态,而从其它的状态转入A或B的工作状态(包括A和B之间相互转换),都要花费一定的启动时间。对于不同的处理节点,这个时间不一定相同。用两个正整数tiA和tiB (i=1,2,...,p)分别表示节点i转入工作状态A和工作状态B的启动时间(单位:ns)。

    2. 一个节点在连续处理同一类任务的时候,执行时间——不含状态转换的时间——随任务量(这一类子任务的数目)的平方增长,即:
      若节点i连续处理x个A类子任务,则对应的执行时间为:t=kiAx2
      类似的,若节点i连续处理x个B类子任务,对应的执行时间为:t=kiBx2
      其中,kiA和kiB是系数,单位是ns,i=1,2,...,p。

    任务分配必须在所有计算开始之前完成,所谓任务分配,即给每个计算节点设置一个任务队列,队列由一串A类和B类子任务组成。两类子任务可以交错排列。

    计算开始后,各计算节点分别从各自的子任务队列中顺序读取计算任务并执行,队列中连续的同类子任务将由该计算节点一次性读出,队列中一串连续的同类子任务不能被分成两部分执行。

    【编程任务】

    现在需要你编写程序,给这 p 个节点安排计算任务,使得这个工程计算任务能够尽早完成。假定任务安排好后不再变动,而且所有的节点都同时开始运行,任务安排的目标是使最后结束计算的节点的完成时间尽可能早。

    【输入输出】

    输入文件名是 hpc.in 。

    文件的第一行是对计算任务的描述,包括两个正整数 nA 和 nB,分别是 A 类和 B 类子任务的数目,两个整数之间由一个空格隔开。

    文件的后面部分是对此计算机的描述:

    文件第二行是一个整数 p ,即计算节点的数目。

    随后连续的 p 行按顺序分别描述各个节点的信息,第 i 个节点由第 i+2 行描述,该行包括下述四个正整数(相邻两个整数之间有一个空格):

    tiA tiB kiA kiB

    输出文件名是 hpc.out 。其中只有一行,包含有一个正整数,即从各节点开始计算到任务完成所用的时间。

    【样例】

    设输入文件hpc.in为
    5 5
    3
    15 10 6 4
    70 100 7 2
    30 70 1 6

    对应的输出文件 hpc.out 为

    93

    【数据说明】

    1 ≤ nA ≤ 60

    1 ≤ nB ≤ 60

    1 ≤ p ≤ 20

    1 ≤ tA ≤ 1000

    1 ≤ tB ≤ 1000

    1 ≤ kA ≤ 50

    1 ≤ kB ≤ 50

    题解

    这题不是很难吧。。。
    首先考虑做一次DP
    预处理出对于每一个节点执行(i)个A任务,(j)个B任务的最短时间
    然后就是一个很简单的DP了
    也就是做两次DP

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    int f1[25][65][65];
    int f2[25][65][65];
    int p,ta[25],tb[25],ka[25],kb[25];
    int na,nb;
    //f1[p][i][j]表示第p个节点执行i个A任务,j个B任务的最短时间
    void DP1()
    {
    	for(int a=1;a<=p;++a)
    	{
    		int F[2][65][65];
    		memset(F,31,sizeof(F));
    		F[1][0][0]=F[0][0][0]=0;
    		for(int i=0;i<=na;++i)
    			for(int j=0;j<=nb;++j)
    			{
    				for(int k=1;k<=i;++k)F[0][i][j]=min(F[0][i][j],F[1][i-k][j]+ka[a]*k*k+ta[a]);
    				for(int k=1;k<=j;++k)F[1][i][j]=min(F[1][i][j],F[0][i][j-k]+kb[a]*k*k+tb[a]);
    				f1[a][i][j]=min(F[0][i][j],F[1][i][j]);
    			}
    	}
    }
    //f2[p][i][j]表示前p个节点执行i个A任务,j个B任务的最短时间
    void DP2()
    {
    	memset(f2,31,sizeof(f2));
    	for(int i=0;i<=na;++i)
    		for(int j=0;j<=nb;++j)
    			f2[1][i][j]=f1[1][i][j];
    	for(int a=2;a<=p;++a)
    	{
    		for(int i=0;i<=na;++i)
    			for(int j=0;j<=nb;++j)
    				for(int k=0;k<=i;++k)
    					for(int l=0;l<=j;++l)
    						f2[a][i][j]=min(f2[a][i][j],max(f2[a-1][k][l],f1[a][i-k][j-l]));
    	}
    }
    int main()
    {
    	freopen("hpc.in","r",stdin);
    	freopen("hpc.out","w",stdout);
    	na=read();nb=read();
    	p=read();
    	for(int i=1;i<=p;++i)ta[i]=read(),tb[i]=read(),ka[i]=read(),kb[i]=read();
    	DP1();
    	DP2();
    	printf("%d
    ",f2[p][na][nb]);
    	return 0;
    }
    
    
  • 相关阅读:
    git 管理
    SVN 管理
    为什么要做静态库
    Sqlite3
    CocoaPod
    内存管理
    readline的用法
    join合并字符串时使用生成器表达式
    pandas DataFrame数据转为list
    Jenkins自动化CI CD流水线之4--Master-Slave架构
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8110967.html
Copyright © 2020-2023  润新知