poj 1018 Communication System

题意:在输入的公司里面,每个公司都要选择一条宽带线,但是能够使用的线的带宽是最“窄”的那根,

每根带宽线都有一个band和一个price;

题目的要求是输出带宽/总价值的最大比值。

例如:

题目中的列子:

1 3
3 100 25 150 35 80 25
2 120 80 155 40
2 100 100 120 110
0.649
第一排的第一个数为测试的个数,第二个数为公司的总数(貌似换行写也没什么的)。
接下来的为各个公司的情况,首先输入这个公司有几种线,然后输入每条线的band和price。
输出的结果的解释:120/(110+40+35) = 0.649  既为第一个公司选择了 150 35,第二个公司选择了155 40
第三个公司选择了120 110.
解题思路:这道题目用贪心的思路来解决是最好的 比较容易理解,因为每一个公司都要选择线,
所以每个公司的band最小的最大值为总band的最小值,每个公司的band最大值的最小值为总能够被选取的band的最小值。
所以总选的band就在这个范围之间。
但是 由于自己是在学习dp 所以这道题目是用的dp的思路。
思路来源:discuss,
代码:
#include <iostream>
using namespace std;
int dp[101][10010];
//dp【i】【j】表示前i个物品最小带宽为j时的最小总和(不表示每一家电器都选了的判断)
struct node
{
 int band;
 int price;
};
int mins(int a,int b)
{
 if(a<b)
  return a;
 else
  return b;
}
void work()
{
 node a[101][101];
 int i,j,k;
 int n;
 int geshu[101];
 int p = 1 ;
 int max = 0;
 int min = 99999;
 scanf("%d",&n);
 for(i = 1 ; i <= n ; i ++)
 {
  scanf("%d",&geshu[p]);
  for(j = 1 ; j <= geshu[p] ; j++)
  {
   scanf("%d%d",&a[i][j].band,&a[i][j].price);
   if(a[i][j].band > max)
    max = a[i][j].band;//找出带宽的最大值
   if(a[i][j].band < min)
    min = a[i][j].band;//貌似加入了 寻找带宽的最大值和最小值结果用的时间多了。
  }
  p++;
 }
 for(i = 1 ; i <= n ; i++)
  for(j = 1 ; j <= max; j++)
   dp[i][j] = 12000; //dp数组的初始值
 for(i = 1 ; i <=geshu[1]; i++)
 {
  if(dp[1][a[1][i].band] > a[1][i].price) //没有直接赋值的原因是可能会出现重复的带宽
   dp[1][a[1][i].band] = a[1][i].price ;
 // cout<<dp[1][a[1][i].band]<<" "<<a[1][i].band<<endl;
 }//只有第一个公司时每个带宽下的最小的price
 for(i = 2 ; i <= n ; i++ )
  for(j = min -1 ; j <= max ; j++)//min-1貌似是多的 但是为了不出错多算一次也没什么的 囧
  {
   if(dp[i-1][j] != 12000)
   {
   // cout<<dp[i-1][j]<<"!!!! "<<j<<endl;
    for(k = 1 ; k <= geshu[i] ; k++)
    {
     int min = j;
     if(a[i][k].band < min)
     {
      min = a[i][k].band;
     }dp[i][min] = mins(dp[i][min],(dp[i-1][j]+a[i][k].price));//好好的体会下这句话
     //如果出现了在当前j的情况下有a[i][k].band 就没有计算dp[i][j]
     //去计算了dp[i][min]的时候继承了在dp[i-1][j]获得的结果下进行动态规划的
   //  cout<<dp[i][min]<<"! "<<min<<endl;
    }
   }
   
  }
 double temp;
 double result = 0;
 /* for(i = 1 ; i <= n ; i++ )
  for(j = 1 ; j <=max ; j++)
  {
   if(dp[i][j] != 12000)
    cout<<dp[i][j]<<" "<<j<<endl;
  }*/
 for(j = min -1 ; j <= max ; j++)//计算比值并找出最大的比值
 {
  if(dp[n][j] != 12000)
  {
  // cout<<j<<" "<<dp[n][j]<<endl;
   temp = (double)j/(double)dp[n][j];
  // cout<<temp<<endl;
   if(temp > result)
    result = temp;
  }
 }
 printf("%.3f/n",result);
}
int main()
{
 int n;
 scanf("%d",&n);
 while(n--)
 {
  work();
 }
 return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值