UVa 690 Pipeline Scheduling


  Pipeline Scheduling 

An arithmetic pipeline is designed to process more than one task simultaneously in an overlap- ping manner. It includes function units and data paths among them. Tasks are processed by pipelining; at each clock, one or more units are dedicated to a task and the output produced for the task at the clock is cascading to the units that are responsible for the next stage; since each unit may work in parallel with the others at any clock, more than one task may be being processed at a time by a single pipeline.


In this problem, a pipeline may have a feedback structure, that is, data paths among function units may have directed loops as shown in the next figure.


Example of a feedback pipeline

Since an arithmetic pipeline in this problem is designed as special purpose dedicated hardware, we assume that it accepts just a single sort of task. Therefore, the timing information of a pipeline is fully described by a simple table called a reservation table, which specifies the function units that are busy at each clock when a task is processed without overlapping execution.


Example of ``reservation table''


clock0123456
unit0X...XX.
unit1.X.....
unit2..X....
unit3...X...
unit4......X


In reservation tables, `X' means ``the function unit is busy at that clock'' and `.' means ``the function unit is not busy at that clock.'' In this case, once a task enters the pipeline, it is processed by unit0 at the first clock, by unit1 at the second clock, and so on. It takes seven clock cycles to perform a task.


Notice that no special hardware is provided to avoid simultaneous use of the same function unit.


Therefore, a task must not be started if it would conflict with any tasks being processed. For instance, with the above reservation table, if two tasks, say task 0 and task 1, were started at clock 0 and clock 1, respectively, a conflict would occur on unit0 at clock 5. This means that you should not start two tasks with single cycle interval. This invalid schedule is depicted in the following process table, which is obtained by overlapping two copies of the reservation table with one being shifted to the right by 1 clock.


Example of ``conflict''


clock01234567
unit001..0C1.
unit1.01.....
unit2..01....
unit3...01...
unit4......01

(`0's and `1's in this table except those in the first row represent tasks 0 and 1, respectively, and `C' means the conflict.)


Your job is to write a program that reports the minimum number of clock cycles in which the given pipeline can process 10 tasks.

Input 

The input consists of multiple data sets, each representing the reservation table of a pipeline. A data set is given in the following format.


\begin{displaymath}\begin{array}{cccc}n & & & \\x_{0,0} & x_{0,1} & \dots & x......_{3,n-1} \\x_{4,0} & x_{4,1} & \dots & x_{4,n-1}\end{array}\end{displaymath}

The integer n(< 20) in the first line is the width of the reservation table, or the number of clock cycles that is necessary to perform a single task. The second line represents the usage of unit0, the third line unit1, and so on. xi,j is either `X' or `.'. The former means reserved and the latter free. There are no spaces in any input line. For simplicity, we only consider those pipelines that consist of 5 function units. The end of the input is indicated by a data set with 0 as the value of n.

Output 

For each data set, your program should output a line containing an integer number that is the minimum number of clock cycles in which the given pipeline can process 10 tasks.

Sample Input 

7
X...XX.
.X.....
..X....
...X...
......X
0

Sample Output 

34


Note: In this sample case, it takes 41 clock cycles to process 10 tasks if each task is started as early as possible under the condition that it never conflicts with any previous tasks being processed.

      | 00000000001111111111222222222233333333334
clock | 01234567890123456789012345678901234567890
-------------------------------------------------
unit0 | 0.1.00112.3.22334.5.44556.7.66778.9.8899.
unit1 | .0.1.....2.3.....4.5.....6.7.....8.9.....
unit2 | ..0.1.....2.3.....4.5.....6.7.....8.9....
unit3 | ...0.1.....2.3.....4.5.....6.7.....8.9...
unit4 | ......0.1.....2.3.....4.5.....6.7.....8.9
(The digits in the table except those in the clock row represent the task number.)


However, it takes only 34 clock cycles if each task is started at every third clock.

      | 0000000000111111111122222222223333
clock | 0123456789012345678901234567890123
------------------------------------------
unit0 | 0..100211322433544655766877988.99.
unit1 | .0..1..2..3..4..5..6..7..8..9.....
unit2 | ..0..1..2..3..4..5..6..7..8..9....
unit3 | ...0..1..2..3..4..5..6..7..8..9...
unit4 | ......0..1..2..3..4..5..6..7..8..9
(The digits in the table except those in the clock row represent the task number.)


This is the best possible schedule and therefore your program should report 34 in this case.



Miguel A. Revilla 
1999-03-05

#include <cstdio>
#include <cstring>

// 总共的时钟数目
int total_num;

// 每个unit所占用情况的二进制表示
// 如果unit0占用情况为00000010,unit[0] = 2
int unit[5];

// able_place[i] = j 代表开始时钟为j和开始时钟为0可以并行
int able_place[30];
int able_count = 0;

// 记录每个任务的开始时钟
int start_clock[10];

// 记录最小时间
int min_time;

bool check(int* p, int x);
void dfs_search(int* p, int x);

int main()
{
	char str[30];
	while(scanf("%d", &total_num) && total_num != 0)
	{
		memset(unit, 0, sizeof(unit));
		memset(able_place, 0, sizeof(able_place));
		memset(start_clock, 0, sizeof(start_clock));
		able_count = 0;
		min_time = 1000;

		// 计算每个unit所占用情况的二进制表示
		for(int i = 0; i < 5; i++)
		{
			memset(str, 0, sizeof(str));
			scanf("%s", str);
			int len = strlen(str);
			for(int j = 0; j < len; j++)
			{
				if(str[j] == 'X')
					unit[i] = unit[i]*2 + 1;
				else
					unit[i] = unit[i]*2;
			}
						
		}

		// 计算与开始时钟为0可以并行的位置
		for(int i = 0; i <= total_num; i++)
		{
			if(check(unit, i))
			{
				able_place[able_count] = i;
				able_count++;
			}
		}
		/*
		printf("it:%d\n", (unit[0]>>3)&unit[0]);
		printf("unit: ");
		for(int i = 0; i < 5; i++)
			printf("%d ", unit[i]);
		printf("\n");
		printf("able: ");
		for(int i = 0; i < able_count; i++)
			printf("%d ", able_place[i]);
		printf("\n");
		*/
		
		// 将第1个任务的位置确定,搜索确定其他任务位置
		start_clock[0] = 0;
		dfs_search(unit, 1);	
		
		printf("%d\n", min_time);					
	}
	return 0;
}

// 检查开始时钟为x能否与开始时钟为0并行,开始时钟为0的分布为p
bool check(int* p, int x)
{
	for(int i = 0; i < 5; i++)
	{
		if(((unit[i]>>x)& p[i]) != 0)
			return false;	
	}	
	return true;
}

//  搜索确定任务x的位置
//  p为最后total_num个位置的布局
void dfs_search(int* p, int x)
{
	if(x == 10)
	{
		if(start_clock[x-1]+total_num < min_time)
		{
			min_time = start_clock[x-1]+total_num;
/*			for(int i = 0; i < 10; i++)
			{
				printf("%d:%d ", i, start_clock[i]);
			}
			printf("\n");
*/		}
		return;
	}

	// 在可行的时钟位置中遍历选择
	for(int i = 0; i < able_count; i++)
	{
		// 剪枝:如果现在选择这个位置,以后的任务不考虑冲突全部选择最小的位置还没有现在的最优解好,就剪枝
		if(start_clock[x-1]+able_place[i] + (9-x)*able_place[0] + total_num >= min_time)
			continue;

		// 否则,检查该位置在当前布局下是否可行
		// 如果可行,就将任务放在该位置,并检查下一任务
		if(check(p, able_place[i]))
		{
			int next_p[5];
			memset(next_p, 0, sizeof(next_p));
			for(int k = 0; k < 5; k++)
			{
				next_p[k] = (p[k] << able_place[i]) ^ unit[k];
			}
			start_clock[x] = start_clock[x-1] + able_place[i];
			dfs_search(next_p, x+1);			
		}			
	}		
}



这是一道好题。
1.最主要的是将判断unit是否冲突改为整数之间的位运算。
以后注意如果只存在0,1,并且在int整数范围内(32位),可以用位运算来进行。
2.剪枝策略不一定能想到。下次做题应该考虑将能计算的东西尽量事先计算好,
比如下一个任务在前一个任务的影响下能放的位置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值