天天看點

poj 1018 Communication System 動态規劃

Communication System

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 25393 Accepted: 9054

Description

We have received an order from Pizoor Communications Inc. for a special communication system. The system consists of several devices. For each device, we are free to choose from several manufacturers. Same devices from two manufacturers differ in their maximum bandwidths and prices. 

By overall bandwidth (B) we mean the minimum of the bandwidths of the chosen devices in the communication system and the total price (P) is the sum of the prices of all chosen devices. Our goal is to choose a manufacturer for each device to maximize B/P. 

Input

The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by the input data for each test case. Each test case starts with a line containing a single integer n (1 ≤ n ≤ 100), the number of devices in the communication system, followed by n lines in the following format: the i-th line (1 ≤ i ≤ n) starts with mi (1 ≤ mi ≤ 100), the number of manufacturers for the i-th device, followed by mi pairs of positive integers in the same line, each indicating the bandwidth and the price of the device respectively, corresponding to a manufacturer.

Output

Your program should produce a single line for each test case containing a single number which is the maximum possible B/P for the test case. Round the numbers in the output to 3 digits after decimal point. 

Sample Input

1 3
3 100 25 150 35 80 25
2 120 80 155 40
2 100 100 120 110      

Sample Output

0.649      

Source

Tehran 2002, First Iran Nationwide Internet Programming Contest

解題報告: 題意: 先輸入測試組數T,之後每組先輸入一個n,代表n種産品, 之後n行,每行先輸入一個數mi,代表第i種産品有mi種型号。之後輸入mi對int,代表mi個不同型号 産品的參數 ,每對第一個是 bandwidth,第二個是price。 現在要求在每種産品中選一個型号。 最終使下列公式的結果 最大。 (所選中n個型号中最小bandwidth值)/(所選中n個型号的price之和)

n最大100,mi最大100。 可以說暴力完全無解。

如果确定一個較好的順序進行計算,那麼可以對每個元素隻處理一遍。

我思考了半天,怎麼做,最後想出來了  感覺上還是比較爽的。 首先這個式子,很複雜。 關鍵是找到一個恰到好處的順序。 我就是看到了那個min(∑ban),怎樣一個順序能使它,對每個元素僅周遊一遍,也就是說能在近乎O(1)的時間算出選擇變化時 min(∑ban)的變化呢? 答案就是做一定的處理 使按照 min(∑ban) 逐漸減小 的順序 計算。

将上去RE,後AC,現總結一下: 1. 數組越界 1)數組開小 我以前出現過的RE錯誤,圖論中和2*maxn大小的數組,常常開成 maxn,該題的maxn*maxn大小數組開成了maxn大小 2)通路出界 單調隊列時,隊列空了還在彈出或删除元素。 2. 分母為0, 這個絕對不可忽視。

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<cctype>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n)  for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n)  for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n)  for(int i=(n) ;i>=0 ;i--)
#define  lson   num<<1,le,mid
#define rson    num<<1|1,mid+1,ri
#define MID   int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
#define mk    make_pair
#define _f     first
#define _s     second
using namespace std;
//const int INF=    ;
typedef long long ll;
//const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
const int INF =0x3f3f3f3f;
const int maxn=  110  ;
//const int maxm=    ;


int num[maxn];
int st[maxn];
int delegate[maxn];
int n,cnt;
int mini;
struct DEV
{
    int b,p;
}dev[maxn][maxn];

bool cmp(DEV x,DEV y)
{
    return x.b>y.b;
}

double ans,tot;

void first_round()
{
     tot=0;
    for(int i=1;i<=n;i++)
    {
        st[i]=num[i]+1;
        delegate[i]=dev[i][1].p;
        for(int j=1;j<=num[i];j++)
        {
            if(dev[i][j].b<mini)  {  st[i]=j ;break;}
//              tmp=min(tmp,dev[i][j]);

            if(dev[i][j].p<delegate[i])  delegate[i]=dev[i][j].p;

        }
        tot+=delegate[i];

    }
//    cout<<ans<<endl;
//    cout<<"mini "<<mini<<" tot "<<tot<<endl;
    ans=max(ans,  mini/tot);
}

struct Node
{
    int b,p,row;
    Node(){}
    Node(int b,int p,int row):b(b),p(p),row(row){}
    bool operator<(const Node &y)const
    {
        return b>y.b;
    }
} a[maxn*maxn];//數組開成maxn*maxn就錯了!!!

void intergrade()
{
    cnt=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=st[i];j<=num[i];j++)//這裡<=num[i]是個容易寫錯的地方
        {
            a[++cnt]=Node(dev[i][j].b,dev[i][j].p,i);
        }
    }
    sort(a+1,a+1+cnt);
}


void second_round()
{
   for(int i=1;i<=cnt;i++)
   {
       int row=a[i].row;
       mini=min(a[i].b,mini);
       tot-=delegate[row];
       tot+=a[i].p;
       delegate[row]=a[i].p;
       ans=max(ans, mini/tot);

   }
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        mini=INT_MAX;ans=-INT_MAX;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            for(int j=1;j<=num[i];j++)
            {
                scanf("%d%d",&dev[i][j].b,&dev[i][j].p);
            }
            sort(dev[i]+1,dev[i]+1+num[i],cmp);
            mini=min(mini,dev[i][1].b);
        }
        first_round();
        intergrade();
        second_round();
        printf("%.3lf\n",ans);


    }


    return 0;
}