版权声明:有女朋友的老江的博客,转载请告知老江 https://blog.csdn.net/qq_42367531/article/details/84102999
【题目描述】
某工厂收到了 n个产品的订单,这 n个产品分别在 A、B 两个车间加工,并且必须先在 A 车间加工后才可以到 B 车间加工。
某个产品 i 在 A,B 两车间加工的时间分别为 Ai,Bi。怎样安排这 n 个产品的加工顺序,才能使总的加工时间最短。
这里所说的加工时间是指:从开始加工第一个产品到最后所有的产品都已在 A,B 两车间加工完毕的时间。
【输入格式】
第一行仅—个数据 n ,表示产品的数量;
接下来 nnn 个数据是表示这 n 个产品在 A 车间加工各自所要的时间;
最后的 nnn 个数据是表示这 n 个产品在 B 车间加工各自所要的时间。
【输出格式】
第一行一个数据,表示最少的加工时间;
第二行是一种最小加工时间的加工顺序。
【样例输入】
5
3 5 8 7 10
6 2 1 4 9
【样例输出】
34
1 5 4 2 3
【数据范围与提示】
对于 100%的数据, 0<n<1000,所有数值皆为整数。
本题的 SPJ 对行尾多余空格敏感,各位输出答案时不要留行尾多余空格~
思路:我好内疚啊,这道其实一点都不难的题我拖了贼久。怎么讲呢?我也不知道啊,但是呢,这道题其实真的不难,可以不用结构体,大概的思路就是排序比较,在排序再比较,最后输出。还有一个就是因为要排序,所以我们一开始就要先定义出一个最小值才可以排序,还有一个可能想不到的是,因为题目要求最后要输出顺序,所以我们必须在一开始最有保存位置的痕迹。不太喜欢在这里打,主要思路全在代码里面,自行理解,超级详细。还有一个就是,有大佬们希望可以帮我解释一下第二个代码当中的为什么要倒着输出?
【代码一,个人全理解,不懂评论】
/*
注意一下题目
题目要求的是要先加工完A车间
才能加工B车间
而且在输入的时候是先输入A车间,再输入B车间的
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()//日常快读
{
char c=getchar();
int x=0,f=1;
while(c<48 || c>57)
{
if(c=='-') f=-1;
c=getchar();
}
while(c>=48 && c<=57)
{
x=x*10+c-48;
c=getchar();
}
return x*f;
}
int a[1100],b[1100];
int m[1100],s[1100];
int ans[1100];
int main()
{
int n; n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) b[i]=read();
for(int i=1;i<=n;i++)
{
m[i]=min(a[i],b[i]);//这一步是为了找出A、B车间的最小值
s[i]=i;
/*
用一个空数组来储存,其实这一步就是把每一个初始化,而且这是顺序是最小的
还有一个就是这个也是当前的这个数的位置,也就是说:某某是第几个数
*/
}
for(int i=1;i<n;i++)//排序
for(int j=i+1;j<=n;j++)
{
if(m[i]>m[j])
/*
m[i]就是之前我们找出来的最小值,
如果我们当前的值比之前的值要小的话
就排序,使得最后的是从小到大生成的
*/
{
swap(m[i],m[j]);//从小到大排序
swap(s[i],s[j]);//把最小的数的位置记录出来
}
}
int k=0,t=n+1;//第一次k++在第一个位置,第一次t--在最后一个位置
for(int i=1;i<=n;i++)//安排加工位置
{
if(m[i]==a[s[i]])//如果我们当前的最小值在A车间里面
{
k++;//那就k++
ans[k]=s[i];//ans记录的最小的k位置更新为当前这个
/*
A用的时间最少,就是使得B车间的等待时间最少
从前往后让B等待时间最少,这样做的原因是因为一定要先做完A车间再做B车间
*/
}
else//如果最小的不是在A车间里面,那就是在B车间里面
{
t--;//那就t--
ans[t]=s[i];//ans记录的最小的t位置更新为当前这个
/*
B用的时间最少,就是使得A车间的等待时间最少
从后往前让A等待时间最少,这样做的原因是因为一定要先做完A车间再做B车间
*/
}
}
k=0; t=0;
for(int i=1;i<=n;i++)//加工最少的时间
{
k+=a[ans[i]];
/*
k是用来保存当前这个A车间的值
(其实a数组当前的储存值是最小的,因为ans代表的是最小的)
只是这个ans[i]有可能属于k的范围也有可能属于t的范围
*/
if(t<k) t=k;
/*
开始的第一步,t一定是小于k的,因为k加了,但是t没加
但是往后的话,t也在增加B车间的最小值,
(ans在前面有记录,所以加得的值是真实的)
t也增加之后就继续比较,之所以要用t输出是有原因的
因为我们是要在B车间完成之后才算结束
所以t表示的是B车间的最小值
所以我们才要用t来与k比较,输出最小值
t=k是什么意思呢?
这个的意思就是说如果你的t比k要小的话,
那么证明当时的t(也就是B车间的最小值)小于k的话,我们就要把t更新为k
k也是最小值只不过是不知道关于谁的最小值
既然是最小值的话,t就可以更新,然后继续比较
而且其实我们换一个角度理解的话,他为什么可以更新呢?
主要是因为要先A后B,所以A车间所用的最小值也是要更新的
大概就是这样,希望可以看得懂吧
*/
t+=b[ans[i]];
/*
t就加回属于自己的B车间的最小值,然后再继续增加A的最小值
就是最小值
*/
}
printf("%d\n",t);
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
//其实我们在前面就已经处理好了最小值的顺序,
//这里直接输出我们所保存的最小值的位置就好了
return 0;
}
【代码二,不懂为什么要倒着】
/*
注意一下题目
题目要求的是要先加工完A车间
才能加工B车间
所以这个就可以有两种情况
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int timeA,timeB,number;//timeA表示的是A车间的时间
//timeB表示的是B车间的时间 //number表示的是编号顺序
}a[1100];
inline int read()//日常快读
{
char c=getchar();
int x=0,f=1;
while(c<48 || c>57)
{
if(c=='-') f=-1;
c=getchar();
}
while(c>=48 && c<=57)
{
x=x*10+c-48;
c=getchar();
}
return x*f;
}
int main()
{
int n; n=read();
for(int i=1;i<=n;i++)
{
a[i].timeA=read();
a[i].number=i;//把当前的顺序存在number里
}
for(int i=1;i<=n;i++) a[i].timeB=read();
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(min(a[i].timeA,a[j].timeB)<min(a[i].timeB,a[j].timeA))
/*
这是两种情况的比较
1.先加工完当前的A车间再加工当前的B车间的时间
2.先加工完其他的A车间再加工当前的B车间的时间
两个方案进行比较,如果第一种小于第二种,就交换
*/
{
swap(a[i],a[j]);
}
}
}
int ans=0,leasttime=0;
//ans表示的是用来比较最小值的时间
//leasttime表示的是最少的时间
for(int i=n;i>=1;i--)//为什么要倒着计算
{
ans+=a[i].timeA;
leasttime=max(ans,leasttime);
leasttime+=a[i].timeB;
}
printf("%d\n",leasttime);//输出最少的时间
for(int i=n;i>=1;i--) printf("%d ",a[i].number);//输出最少时间的顺序
//为什么要倒着输出
return 0;
}