【UVa10498】Happiness-线性规划:单纯形法

测试地址:Happiness
题目大意: N 种食品和M个人,每种食品都有一个价格(每单位 pi ),每个人对每种食品都有一个满意度,一个人的总满意度是他得到的食品量一一乘上对应的满意度,每个人也有一个满意度上限,总满意度不能超过这个上限,规定每个人得到的食品量都必须一一相同,问最多能花掉多少钱,答案向上取整
做法:这一道题需要使用单纯形法解线性规划。
将每个人得到的第 i 种食品量设为xi,那么所有的约束条件都可以表示成 aixibi 的形式,同时所有的 xi 都非负,我们要使得 Mpixi 最大,那么这显然就是一个线性规划的问题,把 pixi 当做目标函数求即可,使用单纯形法即可,这一题的约束条件已经是标准形式了,所以只要松弛变量,初始基本可行解就直接可以找出来了,而且这一题也不用判断无界情况,具体的步骤可以去网上查查资料,这里就不赘述了。注意答案要向上取整。
一种优化方法:使用单纯形法来换基的时候,可以贪心使得每一次转轴变换后目标函数尽可能大,这样时间会得到显著优化。
犯二的地方:理解错题目,以为线性规划的解就是最后的答案,结果还要乘 M <script type="math/tex" id="MathJax-Element-1595">M</script>……
以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define eps 1e-8
#define inf 1e9
using namespace std;
int n,m,p[51];
double matrix[51][51],tmp[51];

void solve()
{
  while(1)
  {
    int k1,k2;
    double mx;
    memset(tmp,0,sizeof(tmp));
    memset(p,0,sizeof(p));

    for(int i=1;i<=n;i++)
      if (matrix[m+1][i]<0)
      {
        double Min=inf;
        for(int j=1;j<=m;j++)
          if (matrix[j][i]>0)
          {
            double t=matrix[j][n+1]/matrix[j][i];
            if (Min>t)
            {
              Min=t;
              p[i]=j;
            }
          }
        if (p[i]) tmp[i]=-matrix[m+1][i]*matrix[p[i]][n+1]/matrix[p[i]][i];
      }

    mx=0.0;
    for(int i=1;i<=n;i++)
      if (tmp[i]>mx) mx=tmp[i],k2=i;
    if (fabs(mx)<eps) break;
    k1=p[k2];
    //贪心

    matrix[k1][k2]=1.0/matrix[k1][k2];
    for(int i=1;i<=n+1;i++)
      if (i!=k2) matrix[k1][i]*=matrix[k1][k2];
    for(int i=1;i<=m+1;i++)
      if (i!=k1)
      {
        for(int j=1;j<=n+1;j++)
          if (j!=k2) matrix[i][j]-=matrix[k1][j]*matrix[i][k2];
      }
    for(int i=1;i<=m+1;i++)
      if (i!=k1) matrix[i][k2]=-matrix[i][k2]*matrix[k1][k2];
    //转轴变换
  }
}

int main()
{
  while(scanf("%d%d",&n,&m)!=EOF)
  {
    memset(matrix,0,sizeof(matrix));
    for(int i=1;i<=n;i++)
    {
      scanf("%lf",&matrix[m+1][i]);
      matrix[m+1][i]=-matrix[m+1][i];
    }
    for(int i=1;i<=m;i++)
      for(int j=1;j<=n+1;j++)
        scanf("%lf",&matrix[i][j]);
    solve();
    int ans=(int)(matrix[m+1][n+1]*m);
    if (matrix[m+1][n+1]*m>ans) ans++;
    printf("Nasa can spend %d taka.\n",ans);
  }

  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值