web-dev-qa-db-ja.com

同等のギフトアルゴリズムの問​​題

問題のリンク- http://opc.iarcs.org.in/index.php/problems/EQGIFTS

ラバニアの誕生日で、数人の家族が誕生日パーティーに招待されました。いつものように、彼ら全員がラヴァーニャと彼女の兄弟ニキルに贈り物を持ってきました。彼らの友人は皆、角質な人なので、誰もが一組の本を持ってきました。残念ながら、贈答者はペアのどの本がLavanya向けで、どれがNikhil向けであるかを明確に示していませんでした。今、これらの本を彼らの間で分割するのは彼らの父親次第です。

彼はこれらのペアのそれぞれから、1冊の本がLavanyaに行き、もう1冊はNikhilに行くことを決めました。さらに、ニキルは贈り物の価値に非常に熱心な観察者であるため、ラバニアの本の合計値がニキルの本の合計値にできるだけ近くなるように、本を分割する必要があります。 LavanyaとNikhilは子供であるため、贈られた本の値が300ルピーを超えることはありません...

問題は、再帰以外は考えられませんでした。私が書いたコードは以下のとおりです。しかし、問題は、コードが時間効率が悪く、10のテストケースのうち9つのテストケースでTLE(Time Limit Exceeded)が発生することです。問題へのより良いアプローチは何でしょうか?

コード-

#include<cstdio>
#include<climits>
#include<algorithm>
using namespace std;

int n,g[150][2];

int diff(int a,int b,int f) {
    ++f;
    if(f==n) {
               if(a>b) {
                       return a-b;
               }
               else {
                    return b-a;
               }
    }
    return min(diff(a+g[f][0],b+g[f][1],f),diff(a+g[f][1],b+g[f][0],f));
}

int main() {
    int i;
    scanf("%d",&n);
    for(i=0;i<n;++i) {
                     scanf("%d%d",&g[i][0],&g[i][1]);
    }
    printf("%d",diff(g[0][0],g[0][1],0));
}

注-これは単なる練習用の質問であり、競技会の一部ではありません。

4
7Aces

朝のステータスミーティングの前に、これを頭のてっぺんから羽ばたくだけです。

Sort books descending by value
Give first book to Lavanya
while books remain
    while Nikhil's values < Lavanya's values
        Give first book to Nikhil
    while Lavanya's values < Nikhil's values
        Give first book to Lavanya

それはそれをしますか?

7
Ben

ベンの答えについての私のコメントについていくつかの混乱があるように見えるので、ここにスタンドアロンのソリューションがあります:

#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <stdlib.h>
using namespace std;

typedef pair<int, int> BookPair;
typedef vector<BookPair*> BookList;

void readBookList(BookList &books)
{
    int n, a, b;
    cin >> n;
    for (int i = 0; i < n; ++i)
    {
        cin >> a >> b;
        int cheapBook = min(a, b);
        int expensiveBook = max(a, b);
        BookPair *bookPair = new BookPair(cheapBook, expensiveBook);
        books.Push_back(bookPair);
    }
}

bool diffsort(BookPair *p1, BookPair *p2)
{
    return abs(p1->first - p1->second) > abs(p2->first - p2->second);
}

void allocate(BookList &books)
{
    int lavanya = 0;
    int nikhil = 0;

    for (BookList::iterator it = books.begin(); it != books.end(); ++it)
    {
        int cheapBook     = (*it)->first;
        int expensiveBook = (*it)->second;

        if (lavanya < nikhil)
        {
            lavanya += expensiveBook;
            nikhil += cheapBook;
        }
        else
        {
            nikhil += expensiveBook;
            lavanya += cheapBook;
        }
    }

    cout << abs(lavanya - nikhil) << endl;
}

int main(int argc, char* argv[])
{
    BookList books;

    readBookList(books);
    sort(books.begin(), books.end(), diffsort);
    allocate(books);

    return 0;
}

基本的に、本のペアを価格の違いで並べ替えます。最初に最大の違いがあります。 (1、3)は(300、300)の前に移動します。次に、本を1ペアずつ割り当て、以前の山のコストが最も高い子供に最も安い本を与えます。

違いはあなたが平準化しようとしているものであるため、本の絶対値ではなく違いでソートします。これにより、(1、201)(150、300)、(150,300)などのセットに関する問題が回避されます。最も公平な割り当ては、1人の子供が300ルピーの本と1ルピーの本の両方を手に入れることです。これにより、他の子供よりも100ルピー多くなります。

代わりに最大の絶対値で並べ替えると、各子供は300ルピーの本を1冊受け取りますが、1人の子供は他の子供より200ルピー多くなります。

1
Karl Bielefeldt

ケビン・クラインはすでにそれを言っていましたが、彼の答えを削除したので、繰り返し説明します。この問題はナップザック問題です。本の各ペアは、それら2冊の価格差で表すことができます。これらの価格差は均等に分散する必要があります。これは、合計がすべての価格差の合計の半分である価格差のサブセットを見つけることに相当します。

例:

Pair   Book1   Book2  Difference
1      100     60     40
2      90      40     50
3      70      50     20
4      65      55     10

差のセットを調べると、{40,50,20,10}、合計は40 + 20 + 50 + 10 =120、したがって、合計が120/2 =60に近いか等しいサブセットを探します。ナップサック問題の既存のアルゴリズムの1つを使用すると、次のようになります。 {50,10}。このサブセットはペアにマッピングして戻すことができるため、一方の子供はペア2と4のより高価な本を取得し、もう一方の子供はペア1と3のより高価な本を取得します。

http://en.wikipedia.org/wiki/Knapsack_problem#Approximation_algorithms は、ナップザック問題の解を近似するためのアルゴリズムについて説明しています。

1
user281377