【poj 3622】Gourmet Grazers

【問題描述】

  與很多奶牛一樣,FJ那羣養尊處優的奶牛們對食物越來越挑剔,隨便拿堆草就能打發她們午飯的日子自然是一去不返了。現在FJ不得不去牧草專供商那裏購買大量美味多汁的牧草,來滿足他那 N 頭挑剔的奶牛。

  所有奶牛都對FJ提出了她對牧草的要求:第i頭奶牛要求她的食物每份的價錢不低於A_i,並且鮮嫩程度不能低於B_i。商店裏供應M種不同的牧草,第i種牧草的定價爲C_i,鮮嫩程度爲D_i 。

  爲了顯示她們的與衆不同,每頭奶牛都要求她的食物是獨一無二的,也就是說,沒有哪兩頭奶牛會選擇同一種食物。FJ想知道,爲了讓所有奶牛滿意,他最少得在購買食物上花多少錢。

【輸入格式】

  第1行: 2個用空格隔開的整數N 和 M。第2..N+1行: 第i+1行包含2個用空格隔開的整數:A_i、B_i。第N+2..N+M+1行: 第j+N+1行包含2個用空格隔開的整數:C_i、D_i

【輸出格式】

  第1行: 輸出1個整數,表示使所有奶牛滿意的最小花費。如果無論如何都無法滿足所有奶牛的需求,輸出-1

【輸入樣例】

4 7
1 1
2 3
1 4
4 2
3 2
2 1
4 3
5 2
5 4
2 6
4 4

【輸出樣例】

12

【樣例解釋】

  給奶牛1吃價錢爲2的2號牧草,奶牛2吃價錢爲4的3號牧草,奶牛3分到價錢爲2的6號牧草,奶牛4選擇價錢爲4的7號牧草,這種分配方案的總花費是12,爲所有方案中花費最少的。

【數據範圍】

1<=N,M<=100,000
1 <= A_i,C_i,D_i<=1,000,000,000

【來源】
USACO 2007 Gold

題目大意:給你n頭奶牛對價格的需求A[i]和鮮嫩度需求B[i],再給你m個牧草的信息,要求讓所有的牛都匹配到牧草且使得總花費最小。
算法&知識點:匹配型的貪心。
先考慮奶牛鮮嫩度需求最小的奶牛,在所有能夠滿足它對價格和鮮嫩度需求的牧草中選擇一個價格最小的。鮮嫩度也較小的。然後標記這個牧草已經被使用過。下一次繼續查找直到考慮完所有的奶牛。如果有奶牛不能匹配到牧草就是無解。
優化:將上面每一個滿足條件的牧草放到一個以價格爲關鍵字的multiset中,查找時只需要調用O(log2m)的s.lower_bound()即可,可以節省時間。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<algorithm>
#include<cstring>
#include<set>
using namespace std;
typedef long long LL;
const int maxn=100010;
int n,m,vis[maxn];
struct cow
{
    int a,b;
}A[maxn],B[maxn];//牧草和奶牛有共同屬性,故只需要定義一個結構體

bool cmp(cow a,cow b)//把奶牛和牧草按照鮮嫩度由大到小排序
{
    return a.b>b.b;
}
struct cmp2//仿函數
{
    bool operator()(cow a,cow b)
    {
        return a.a<b.a;
    }
};

multiset<cow,cmp2>s;
multiset<cow,cmp2>::iterator it;
int main()
{
    //freopen("cate.in","r",stdin);
    //freopen("cate.out","w",stdout);

    scanf("%d%d",&n,&m);

    for(int i=1;i<=n;i++)
    scanf("%d%d",&A[i].a,&A[i].b);
    for(int i=1;i<=m;i++)
    scanf("%d%d",&B[i].a,&B[i].b);

    sort(A+1,A+n+1,cmp);
    sort(B+1,B+m+1,cmp);

    LL sum=0;
    bool ok=1;
    int j=1;
    for(int i=1;i<=n;i++)
    {
        while(j<=m && B[j].b>=A[i].b)//將滿足條件的草壓入多重集
        {
            s.insert(B[j]);
            j++;
        }

        it=s.lower_bound(A[i]);

        if(it==s.end())//如果找不到匹配的草
        {
            ok=0;
            break;
        }

        sum+=it->a;
        s.erase(it);
    }   
    if(!ok)printf("-1\n");
    else cout<<sum<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章