程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ 1018 Communication System [枚舉]

POJ 1018 Communication System [枚舉]

編輯:C++入門知識

大致題意:
某公司要建立一套通信系統,該通信系統需要n種設備,而每種設備分別可以有m1、m2、m3、...、mn個廠家
提供生產,而每個廠家生產的同種設備都會存在兩個方面的差別:帶寬bandwidths 和 價格prices。
現在每種設備都各需要1個,考慮到性價比問題,要求所挑選出來的n件設備,要使得B/P最大。
其中B為這n件設備的帶寬的最小值,P為這n件設備的總價。

 


解題思路:


首先需要明確,要使得B/P最大,自然是要令B盡可能大,P盡可能小。

由於B和P是兩個相互制約的變量,而他們又要同時取得盡可能地取極值,那麼可以先令其中一個值“暫時固定”下來。

令輸入的行數就是設備的種類數,即第i行描述的是第i種設備,及提供第i種設備的廠家的產品信息。

 

使用枚舉+剪枝的做法:

首先B的值肯定是廠家生產的所有設備中的某個帶寬值,所以可以枚舉所有的帶寬,每次枚舉B值時,B值就被“暫時固定”了。

其次,記錄所選取的B是屬於第k種設備的,再從余下的設備中,選取其余n-1種設備各一個,要求所選取的設備的帶寬>=B(這是由題意確定的),而價格是要滿足帶寬的要求下的最小值。

當n種設備都選取後,計算B/P,然後再枚舉下一個B,重復上述操作。比較不同的B值所得到的B/P值,選取最大的一個就是答案。

 

剪枝法:

准備工作:

1、輸入時先記錄:對於每種設備,廠家所提供的最大帶寬MaxB[]

2、對所有設備(無論是否同種類)進行升序快排,以帶寬為第一關鍵字,價格為第二關鍵字,設備所屬的種類編號(1~n)為第三關鍵字。排序後存放在一維數組dev[]

剪枝:

1、  從小到大枚舉dev[]中各個設備的帶寬作為B值,設總設備數位m,則從1枚舉到m-(n-1)。這是因為至少需要選擇從枚舉位置開始後面的n種設備,m-(n-1)是上限值,即恰好最後n件設備分別為n種設備。

2、  枚舉B值的過程中,若發現B值比某種設備的最大帶寬更大,則無需繼續枚舉,輸出前面得到的B/P值。這是因為B是所有設備的最小帶寬,若出現某個設備的最大帶寬比B小,則說明B的選擇是不合法的,又dev[]已按B升序排序,後面的B值更大,也不可能成立,因此無需繼續枚舉。

3、  枚舉B值過程中,對於每個B值,在選擇其他設備時要記錄選取不同種類的設備個數count。最後當count<n時,說明B值位置往後剩余的設備中已無法提供n-1種不同設備,可直接跳出枚舉。

-----------------------------//上面分析轉自:優YoU http://blog.csdn.net/lyy289065406/article/details/6676781

我的代碼:

P.S. 在HDU上用GNU C++ 一直是 WA ,但是在POJ上用 C++ 交就能過(

Accepted 312K 110MS C++
),真心搞不懂。。


[cpp]
#include <cstdio>  
#include <cstring>  
#include <algorithm>  
using namespace std; 
#define N 101  
struct NODE 

    int b;//寬帶  
    int p;//價格  
    int id;//設備編號  
}; 
//按帶寬、價格、編號依次比較排序  
int cmp(const void* a, const void* b) 

    NODE* x =(NODE*)a; 
    NODE* y =(NODE*)b; 
    if((x->b)==(y->b)) 
    { 
        if((x->p)==(y->p)) 
            return (x->id) -(y->id); 
        else 
            return (x->p) - (y->p); 
    } 
    return (x->b) -(y->b); 

 
double max(double a, double b) 

    return a > b? a:b; 

int MaxB[N]; //各種設備對應的帶寬最大值  
NODE dev[N*N]; //記錄所有廠家生產的產品信息  
bool vist[N]; 
int pd; //dev[]指針  
 
int main() 

    int test, i, j; 
    //freopen("in.txt","r",stdin);  
    scanf("%d",&test); 
    while(test--) 
    { 
        int n;//設備數  
        int m = 0; //生產商總數  
        pd = 0; 
        scanf("%d",&n); 
        for(i=1;i<=n;i++) 
        { 
            int mi; 
            scanf("%d",&mi); 
            m +=mi; 
            MaxB[i] =-1; 
            for(j=1;j<=mi;j++) 
            { 
                pd++; 
                scanf("%d%d",&dev[pd].b,&dev[pd].p); 
                dev[pd].id=i; 
                MaxB[i] = max(MaxB[i], dev[pd].b); 
            } 
        } 
        qsort(dev,m+1,sizeof(NODE),cmp); 
 
        bool flag = false; 
        double ans = 0; // B/P的最大值  
        for(i=1;i<=m-(n-1);i++) //枚舉所有設備帶寬的最小帶寬B  
        {           //m-(n-1)是剪枝,因為當設備數>生產商時就不必枚舉了  
            memset(vist,false,sizeof(bool)*(n+1)); 
            vist[dev[i].id] = true; 
            double price = dev[i].p; //設備總價  
            int count = 1;   //計數器,記錄已經選取的設備個數  
            for(j=i+1;j<=m;j++) 
            { 
                if(vist[ dev[j].id]) 
                continue; 
                if(dev[i].b > MaxB[dev[j].id]) //剪枝  
                { 
                    flag= true;  //當前枚舉的“所有設備帶寬的最小帶寬Bi”比“設備j的最大帶寬MaxBj”要大  
                //說明當前Bi已經越界,無需繼續往後枚舉  
                    break; 
                } 
                vist[dev[j].id] =true; 
                price +=dev[j].p; 
                count++; 
            } 
            if(flag || count<n) 
                break; 
            ans = max(ans, (dev[i].b/price)); 
        } 
        printf("%.3lf\n",ans); 
    } 
    return 0; 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 101
struct NODE
{
    int b;//寬帶
    int p;//價格
    int id;//設備編號
};
//按帶寬、價格、編號依次比較排序
int cmp(const void* a, const void* b)
{
    NODE* x =(NODE*)a;
    NODE* y =(NODE*)b;
    if((x->b)==(y->b))
    {
        if((x->p)==(y->p))
            return (x->id) -(y->id);
        else
            return (x->p) - (y->p);
    }
    return (x->b) -(y->b);
}

double max(double a, double b)
{
    return a > b? a:b;
}
int MaxB[N]; //各種設備對應的帶寬最大值
NODE dev[N*N]; //記錄所有廠家生產的產品信息
bool vist[N];
int pd; //dev[]指針

int main()
{
    int test, i, j;
    //freopen("in.txt","r",stdin);
    scanf("%d",&test);
    while(test--)
    {
        int n;//設備數
        int m = 0; //生產商總數
        pd = 0;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            int mi;
            scanf("%d",&mi);
            m +=mi;
            MaxB[i] =-1;
            for(j=1;j<=mi;j++)
            {
                pd++;
                scanf("%d%d",&dev[pd].b,&dev[pd].p);
                dev[pd].id=i;
                MaxB[i] = max(MaxB[i], dev[pd].b);
            }
        }
        qsort(dev,m+1,sizeof(NODE),cmp);

        bool flag = false;
        double ans = 0; // B/P的最大值
        for(i=1;i<=m-(n-1);i++) //枚舉所有設備帶寬的最小帶寬B
        {    //m-(n-1)是剪枝,因為當設備數>生產商時就不必枚舉了
            memset(vist,false,sizeof(bool)*(n+1));
            vist[dev[i].id] = true;
            double price = dev[i].p; //設備總價
            int count = 1;   //計數器,記錄已經選取的設備個數
            for(j=i+1;j<=m;j++)
            {
                if(vist[ dev[j].id])
                continue;
                if(dev[i].b > MaxB[dev[j].id]) //剪枝
                {
                    flag= true;  //當前枚舉的“所有設備帶寬的最小帶寬Bi”比“設備j的最大帶寬MaxBj”要大
    //說明當前Bi已經越界,無需繼續往後枚舉
                    break;
                }
                vist[dev[j].id] =true;
                price +=dev[j].p;
                count++;
            }
            if(flag || count<n)
                break;
            ans = max(ans, (dev[i].b/price));
        }
        printf("%.3lf\n",ans);
    }
    return 0;
}

 

 

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved