【bzoj2666】【cqoi2012】【组装】【贪心】

Description
数轴上有m个生产车间可以生产零件。一共有n种零件,编号为1~n。第i个车间的坐标为xi,生产第pi种零件(1<=pi<=n)。你需要在数轴上的某个位置修建一个组装车间,把这些零件组装起来。为了节约运输成本,你需要最小化cost(1)+cost(2)+…+cost(n),其中cost(x)表示生产第x种零件的车间中,到组装车间距离的平方的最小值。
Input
输入第一行为两个整数n, m,即零件的种类数和生产车间的个数。以下m行每行两个整数xi和pi(1<=pi<=n)。输入按照生产车间从左到右的顺序排列(即xi<=xi+1。注意车间位置可以重复)。输入保证每种零件都有车间生产。
Output
输出仅一行,即组装车间的最优位置(可以和某个生产车间重合),四舍五入保留四位小数。输入保证最优位置惟一。
Sample Input
3 5
-1 3
0 1
2 3
4 2
5 2
Sample Output
2.0000
HINT
1-4 n<=15 m<=25 xi<=100
5-10 n<=10000 m<=100000 xi<=100,000
题解:
设最优位置为x.

ans=ni=1(xxi)2
      =nx22xni=1xi+ni=1x2i
x=ni=1xin 时取得最小值.
此时 ans=ni=1x2i(ni=1xi)2n

A=ni=1x2i
B=(ni=1xi)2n
我们现在只要最小化A-B即可.
我们把每种零件取得最值的位置设为它出现的第一个位置.
设{x,y}表示一个替换,y是x位置的零件种类的下一个位置.
我们可以把所有的替换找出来,依次考虑.
首先把所有的替换按(x+y)从小到大排序.
这样保证每次替换之后对于后面的决策被替换掉的一定不会再成为这个种类的最优解.
证明可以看这里
http://www.cnblogs.com/jianglangcaijin/p/4204478.html
然后依次替换即可.
代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 10010
using namespace std;
int n,m,x,y,point[N],cnt,f[N];
double P,S,ans,t;
struct use{int a,b,v;}e[N*20];
bool cmp(use a,use b){return a.v<b.v;}
int main(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<=m;i++){
    scanf("%d%d",&x,&y);
    if (!f[y]) point[y]=x,f[y]=1,P+=(double)x*x,S+=(double)x;
    else{
      e[++cnt]=use{point[y],x,(point[y]+x)};
      point[y]=x;
    }
  }
  ans=P-(S*S)/(double)n;
  t=S/(double)n;
  sort(e+1,e+cnt+1,cmp);    
  for (int i=1;i<=cnt;i++){
    double t1=P,t2=S;double temp;
    t1=(double)(t1-(double)e[i].a*e[i].a+(double)e[i].b*e[i].b);
    t2=(double)(t2-(double)e[i].a+(double)e[i].b);
    temp=(t1-(t2*t2)/(double)n);
    P=t1;S=t2;
    if (temp<ans){
       ans=temp;
       t=S/(double)n;
    }
  }
  printf("%.4lf\n",t);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值