题意:
一个鞋匠要做n双鞋,每一双鞋需要花费的时间是t;鞋匠每天只能做一双鞋,如果一双鞋没有按时完成,则每耽误一天罚款s。
现在依次输入n双鞋所需要的时间和罚款,求一个罚款最小的安排。
思路:
开始觉得可以将罚款多的放在前面做,但后面发现这种贪心策略是不正确的。后面考虑了一下,可以按每双鞋s/t从大到小进行一个排序
如果值相同则编号小的放前面(因为他要求输出最小字典序的答案);那么这种贪心为什么是正确的?我们考虑中间一个排。。。。。ab。。。。。
a,b前面和后面的罚款都是和a,b的排列无关的,所以我们如果使得a,b的罚款数最小就可以减少总的罚款数。
a,b的排列有两种ab和ba。设a,b前面已产生的罚款为m,则ab排列时罚款为m*Sa+Sb*(m+Ta) ,ba排列时罚款为m*Sb+Sa*(m+Tb);
如果我们假设ab排列优于ba排列可得:
m*Sa+Sb*(m+Ta)<=m*Sb+Sa*(m+Tb);整理可得 Sa/Ta>=Sb/Tb;
然后我们对所有的相邻元素运用这个策略就可以得到上面的贪心方法了。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef struct
{
int i;
double x;
}P;
P p[1100];
int cmp(P p1,P p2)
{
if(p1.x==p2.x)
return p1.i<p2.i;
return p1.x>p2.x;
}
int main()
{
int i,n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=0;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
p[i].x=1.0*y/x;
p[i].i=i;
}
sort(p,p+n,cmp);
for(i=0;i<n-1;i++)
printf("%d ",p[i].i+1);
printf("%d\n",p[n-1].i+1);
if(t)
printf("\n");
}
return 0;
}