【HAOI2010】工厂选址题解

题目描述

某地区有m座煤矿,其中第i号矿每年产量为ai吨,现有火力发电厂一个,每年需用煤b吨,每年运行的固定费用(包括折旧费,不包括煤的运费)为h元,每吨原煤从第i号矿运到原有发电厂的运费为Ci0(i=1,2,…,m)。

现规划新建一个发电厂,m座煤矿每年开采的原煤将全部供给这两座发电厂。现有n个备选的厂址。若在第j号备选厂址建新厂,每年运行的固定费用为hj元。每吨原煤从第i号矿运到j号备选厂址的运费为Cij(i=1,2,…,m;j=1,2,…,n)。

试问:应把新厂厂址选取在何处?m座煤矿开采的原煤应如何分配给两个发电厂,才能使每年的总费用(发电厂运行费用与原煤运费之和)为最小。

输入输出格式

输入格式:

 

第1行: m b h n

第2行: a1 a2 … am (0<=ai<=500, a1+a2+...+an>=b)

第3行: h1 h2 … hn (0<=hi<=100)

第4行: C10 C20 … Cm0 (0<=Cij<=50)

第5行: C11 C21 … Cm1

… …

第n+4行:C1n C2n … Cmn

 

输出格式:

 

第1行:新厂址编号,如果有多个编号满足要求,输出最小的。

第2行:总费用

说明

对于所有数据, n<=50, m<=50000, b<=10000

题解

  我们看到这道题的数据,发现工厂的数量不会多余50个,所以我们可以考虑枚举新的工厂的选址。

  然后,问题就转化为了两个工厂如何分配资源使得总花费最小,我们可以利用贪心的思想来做:

  如果所有的资源都汇集到新建的厂(now),那么花费就为∑(a[i]*c[i][now]),然后我们要从所有的资源中提取出b的资源使得这个值最小,所以我们可以记录w[i] = c[i][now] - c[i][0]表示把i的资源移到原工厂每吨会多花多少钱。然后我们在以此排序贪心即可。

  这种贪心的思想是利用的一种差值,这个差值的实际含义为:在把所有的关键量都放在一个组中达到一个定值,然后在从中移取出一部分,而达到的新的量就是新的花费减去不用的花费在这种情况下我们就可以使用差值来贪心。

程序

 #include<bits/stdc++.h>
 using namespace std;
 
 int b, m, n, h;
 int c[50005][55], cost[55], a[50005];
 struct Fact{
     int pos, val;
 }w[50005];
 
 inline bool comp(const Fact & x, const Fact & y)    {return x.val > y.val;}
 
 int main()
 {
     int sumcost = 0x7fffffff, num, tag, ans;
     scanf("%d%d%d%d", &m, &b, &h, &n);
     for(int i = 1; i <= m; ++ i)    scanf("%d", &a[i]);
     for(int i = 1; i <= n; ++ i)    scanf("%d", &cost[i]);
     for(int i = 1; i <= m; ++ i)    scanf("%d", &c[i][0]);
     for(int i = 1; i <= n; ++ i)
         for(int j = 1; j <= m; ++ j)
             scanf("%d", &c[j][i]);
     for(int i = 1; i <= n; ++ i)
         {
             tag = 0, ans = 0;
             for(int j = 1; j <= m; ++ j)
                 {
                     w[j].val = c[j][i] - c[j][0];
                     w[j].pos = j;
                 }
             sort(w + 1, w + 1 + m, comp);
             int k = 0;
             for(;;)
                 {
                     ++ k;
                     if(tag + a[w[k].pos] > b)
                         {
                             ans += c[w[k].pos][0] * (b - tag);
                             ans += c[w[k].pos][i] * (a[w[k].pos] - (b - tag));
                             break; 
                         }
                     tag += a[w[k].pos];
                     ans += c[w[k].pos][0] * a[w[k].pos];
                 }
             for(;k <= m;)    ++ k, ans += c[w[k].pos][i] * a[w[k].pos];
             ans += h + cost[i];
             if(sumcost > ans)
                 {
                     sumcost = ans;
                     num = i;
                 }
         }
     printf("%d\n%d\n", num, sumcost);
     return 0;
 }

 

转载于:https://www.cnblogs.com/2020pengxiyue/p/9459988.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值