题目描述
在硬件小学期课程上,学生们要分组使用Verilog编写流水线CPU,并学会处理各种流水线CPU中常见的相关问题,包括数据相关、结构相关与控制(转移)相关,炸鸡块君也学到了许多。现在,他也要教你解决流水线CPU中数据相关下的先写后读相关问题。
在汇编语言程序中,程序是由多句汇编语句组成的,每句汇编语句会从寄存器中读一些数据(可能不读)和向寄存器中写一些数据(可能不写)。但由于CPU流水线式的架构,一条语句A写入寄存器的数据若想被语句B读到,则语句B和A之间至少要间隔三条语句,否则B将读到该寄存器中的老数据而不是A刚刚写入的数据,这被称为寄存器的先写后读相关问题。
例如,第一条语句写入了十号寄存器一个数据,若想写一个读取十号寄存器中数据的语句,则该语句最快也要等到第五句才可以(因为此时两条语句才恰好间隔三句)。
解决先写后读相关问题往往可以使用插入空操作(空操作也是一种汇编语句,该语句什么都不做,只起到占位的作用)的方法,即填充一些什么都不做的语句到原程序中。例如,现在第一条语句写入了八号寄存器、第二条语句读取了八号寄存器,因此存在对八号寄存器的先写后读相关问题,可以通过在之中插入三句空语句来解决该问题,即原程序在插入后变为:原第一条语句、空语句、空语句、空语句、原第二条语句。
现在,给出一个原有nnn个语句的汇编程序,并给出程序中语句之间发生先写后读相关的情况,请你求出最少添加多少个空语句可以使得该程序完全不存在任何先写后读相关问题。
输入描述:
输入第一行包括一个整数n(3≤n≤100),程序原有语句总数。接下来有n行,第i行描述了第iii条程序语句,每行有三个数字。第i行第j个数字aij∈{0,1}表示第i句与第i−j句间是否发生了先写后读相关,为1表示有发生先写后读相关(即第i−j句写入了某一寄存器,而第i句又要读取同一寄存器),为0表示没有。输入保证对于i−j≤0的aij有aij=0成立(你可以通过样例进一步理解输入的含义)
输出描述:
输出一个整数,表示为完全消除先写后读相关至少需加入多少条空语句。
示例1
输入
4 0 0 0 1 0 0 0 1 0 0 0 0
输出
3
说明
输入表示发生先写后读相关问题的语句有:第二句读了第一句所写的寄存器、第三句读了第一句所写的寄存器。
一种插入三个空语句的最优策略为变成:
原第一句、空语句、空语句、空语句、原第二句、原第三句、原第四句。
题意
题目看起来很长,但很多都是没用的直接讲样例就好了第二行是1 0 0 (1是在第一个的所以是前两句也就是第一句的寄存器)说明第二句读了第一句的寄存器 所以第二句和第一句直接要相隔三条语句 所以插入三条空语句 第三行是0 1 0 (1是在第二个的所以是前两句也就是第一句的寄存器)说明第三句读了第一句的寄存器 但他和第一句之间已经隔了四条语句所以不用再插入语句 第四行全是0就没有需要读入的语句;如果有一行是1 1 1这种情况的那我们只需要算最前面1的就可以了
思路
用两个数组a,b; a数组是记录当前位置需要读第几句,b数组用来记录插入空语句后的句子;就按照样例来说a={0,1,1,0};b={1,0,0,0,2,3,4},0就是空语句我们只要模拟这个过程就可以了
#include "bits/stdc++.h"
using namespace std;
int main(){
int n;
int mp[1005][5];
int a[1005];
int b[1005];
cin>>n;
for(int i=1;i<=n;i++){
a[i]=4;
for(int j=1;j<=3;j++){
cin>>mp[i][j];
if(mp[i][j]==1) a[i]=min(a[i],j);
}
}
int cnt=0;
for(int i=1;i<=n;i++){
if(a[i]!=4){
int k=cnt;
while(b[k]!=i-a[i]) k--;
int num=3-(cnt-k);
for(int j=1;j<=num;j++){
cnt++;
b[cnt]=0;
}
}
cnt++;
b[cnt]=i;
}
cout<<cnt-n<<endl;
}