原题:
我们现在要利用m台机器加工n个工件,每个工件都有m道工序,每道工序都在不同的指定的机器上完成。每个工件的每道工序都有指定的加工时间。 每个工件的每个工序称为一个操作,我们用记号j-k表示一个操作,其中j为1到n中的某个数字,为工件号;k为1到m中的某个数字,为工序号,例如2-4表示第2个工件第4道工序的这个操作。在本题中,我们还给定对于各操作的一个安排顺序。 例如,当n=3,m=2时,“1-1,1-2,2-1,3-1,3-2,2-2”就是一个给定的安排顺序,即先安排第1个工件的第1个工序,再安排第1个工件的第2个工序,然后再安排第2个工件的第1个工序,等等。 一方面,每个操作的安排都要满足以下的两个约束条件。 (1) 对同一个工件,每道工序必须在它前面的工序完成后才能开始; (2) 同一时刻每一台机器至多只能加工一个工件。 另一方面,在安排后面的操作时,不能改动前面已安排的操作的工作状态。 由于同一工件都是按工序的顺序安排的,因此,只按原顺序给出工件号,仍可得到同样的安排顺序,于是,在输入数据中,我们将这个安排顺序简写为“1 1 2 3 3 2”。 还要注意,“安排顺序”只要求按照给定的顺序安排每个操作。不一定是各机器上的实际操作顺序。在具体实施时,有可能排在后面的某个操作比前面的某个操作先完成。 例如,取n=3,m=2,已知数据如下: 则对于安排顺序“1 1 2 3 3 2”,下图中的两个实施方案都是正确的。但所需要的总时间分别是10与12。 当一个操作插入到某台机器的某个空档时(机器上最后的尚未安排操作的部分也可以看作一个空档),可以靠前插入,也可以靠后或居中插入。为了使问题简单一些,我们约定:在保证约束条件(1)(2)的条件下,尽量靠前插入。并且,我们还约定,如果有多个空档可以插入,就在保证约束条件(1)(2)的条件下,插入到最前面的一个空档。于是,在这些约定下,上例中的方案一是正确的,而方案二是不正确的。 显然,在这些约定下,对于给定的安排顺序,符合该安排顺序的实施方案是唯一的,请你计算出该方案完成全部任务所需的总时间。
输入
第1行为两个正整数m和n(其中m(<20)表示机器数,n(<20)表示工件数),用一个空格隔开:
第2行:个用空格隔开的数,为给定的安排顺序。
接下来的2n行,每行都是用空格隔开的m个正整数,每个数不超过20。
其中前n行依次表示每个工件的每个工序所使用的机器号,第1个数为第1个工序的机器号,第2个数为第2个工序机器号,等等。
后n行依次表示每个工件的每个工序的加工时间。
输出
只有一个正整数,为最少的加工时间。
样例输入
2 3
1 1 2 3 3 2
1 2
1 2
2 1
3 2
2 5
2 4
样例输出
10
我就想大概题目都没有人看完是吧,甚至看完了题目之后是不是感觉还没有理解,我觉得有个完整的题目和配图已经不错了,毕竟当时个人在某个编程网站上看到的题目残缺不全,甚至看了好久也没有看明白题目。
首先,我们就来理解一下题目:
- 就是有两台不同的机器a,b(题目里只有两台机器,为了更好理解就具体表示出来).
- 两台机器,每台机器同一时间只能做一个工序。
- 文章里有3个工件,每个工件有2道工序(姑且叫做1,2),有2台机器。
- 还要注意,“安排顺序”只要求按照给定的顺序安排每个操作。不一定是各机器上的实际操作顺序。这句话什么意思? 意思就是工件局部是必须有序的,但是对于全部的工价它是不一定有序的,就如题目中提供的 1-1,1-2,2-1,3-1,3-2,2-2。你看他的这个次序,我做完2-1,那么我必须先做3-1吗? 不是,我做完2-1,我可以去做2-2,不一定要做2-1后面的3-1,这就是不一定是各机器上的实际操作的意思。那第二句什么意思?又说有序?有序其实就是工件局部必定是有序的,就是向上面的那个序列,你不可能先做2-2再做2-1,你不可能先做3-2再做3-1,但是这就很坑--------原题和输入数据的第三个工件的次序不一样,你看输入的次序是什么。
1 2
1 2
2 1
第一行是第一个工件,第二行是第二个工件,第三行是第三个工件,每个工件2道工序,你看第三个,第二道工序在前面。。。。。。。。。。(ctm)
然后是对应的时间:
3 2
2 5
2 4
对应的分别是1-1,1-2,2-1,2-2,3-2,3-1。
理解完题目之后那就简单了,大概意思就是让两台机器尽可能的不违反两条前提工作嘛,万恶的资本主义。。。。。
做算法题,最主要的是理解数据与数据之间的关系,这样的题目完全可以通过数据结构来完成,因为数据结构本就是数据关系的集合,但是我们首先先用传统的方法来解决。
先理解数据之间的联系:
有三个工件,而且都有不同的工件编号(1,2,3);
每个工件都有两道工序(1,2),而且每道工序都有给定的时间(3 2 2 5 2 4)。
大概就是上面的关系了,所以我们需要三个容器来存储上面三个数据,一个是工件号(1 1 2 3 3 2),一个是工序号(1 2 1 2 2 1),最后一个是每道工序的时间(3 2 2 5 2 4)。
然后还有两台(m)机器(m1,m2),每台机器都可以运行。
剩下的就是代码实现:
#include<stdio.h>
#include<string.h>
int step[199];//工件的工序,对应的是工件号
int num[22][22];//工件对应的机器
int time[22][22];//每道工序对应的时间,为0表示已经执行
int lasttime[22][22]={0};//工件每道工序最后完成的时间
int madecine[22][22]={0};//机器对应的运行时间
int main()
{
int n,m;
scanf("%d%d",&m,&n);
int i,j;
for(i=1;i<n*m;i++)
scanf("%d",&step[i]);//存储的是工件号(1 1 2 3 3 2)
for(i=1;i<=n;i++)//都从1开始,更好理解
for(j=1;j<=m;j++)
scanf("%d",&num[i][j]);//存储的是机器号(1 2 1 2 2 1)
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&time[i][j]);//存储的是工序对应的时间(3 2 2 5 2 4)
int s=0,fi=0,x;
for(i=1;i<=n*m;i++)//共有m*n道工序
{
s=0;
j=1;
while(time[step[i]][j]==0) j++;//j都是从1开始的,但是这不一定是它的工序号,如第三个工件1对应的是2,2对应的是1
int gj=step[i];
for(x=lasttime[gj][j-1]+1;;x++)//last[][]初始化是为0,x最初为1,后续是某个工件某个工序完成的时间+1
/*寻找机器可执行时间段*/
{
if(madecine[num[gj][j]][x]==0)//num[gj][j]对应的是机器号,意思就是每台机器对应的时间点是否已经用过了,没有用过则加的去
s++;
else s=0;//否则,在从x时间点开始道x+s这个时间段不足以满足当前工序所需要的时间
if(s>=time[step[i]][j]) break;//找到即退出
}
lasttime[gj][j]=x;//找到一个符合的时间段x
if(x>fi) fi=x;//记录最晚的时间
while(time[gj][j]!=0) //将用了的时间段占值
{
madecine[num[gh][j]][x]=1;//x是当前机器对应的最后时间
x--;//把前面的时间都置为1
time[gj][j]--;//该工序时间减一,最后退出循环之时为0,表示该工序已经完成。
}
}
printf("%d\n",fi);
return 0;
}
用数据结构做原理相同:
#include<stdio.h>
struct node {
int id;//在第id个机器上加工
int cost;//花费的时间
} w[21][21];//w[i][j]表示第i个物品,第j个工序
int m,n;
int order[500];//用来存储给定的做工顺序
int step[21]= {0};//step[i]存储第i个物品当前进行到的工序号
int last_time[21]= {0};//该物品上一个工序完成的时间
int mac[21][100000]={0};//mac[i][j]表示第i个机器在时间点j是否空闲
int ans=0;
int main() {
scanf("%d%d",&m,&n);
for(int i=1; i<=m*n; i++) {
scanf("%d",&order[i]);
}
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
scanf("%d",&w[i][j].id);
}
}
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
scanf("%d",&w[i][j].cost);
}
}
//对order序列进行处理
for(int i=1; i<=m*n; i++) {
int now = order[i];//当前要处理的物品编号
int k = step[now];//当前是第几个工序
k++;
step[now]=k;
//找出now这个物品需要在哪个机器上加工,及其时间
int id = w[now][k].id;
int cost = w[now][k].cost;
int s = 0;//能分配到的时间累计
//在对应的机器上找空余的时间段
for(int j=last_time[now]+1; ; j++) {
if(mac[id][j]==0) {
s++;//空余时间+1
} else {
s=0;//从0开始累计,因为我们需要的是一整段连续的空余时间,而不是断断续续的时间
}
if(s==cost) {//到目前为止分配的时间够用,那就用
for(int p = j - cost + 1; p<=j; p++) {
mac[id][p] = 1;//表示被使用,给他一个标记
}
if(j>ans) ans=j;//更新答案
last_time[now] = j;//更新工序完成的时间
break;//跳出循环
}
}
}
printf("%d\n",ans);
return 0;
}