HDU 1538 A Puzzle for Pirates 海盗分金问题

题目大意:

就是现在n个海盗分配m枚金币, 依次编号为P1~Pn

然后海盗按照Pn->P(n - 1)->...->P2->P1的顺序提出分配方案, 然后或者的海盗投票表示是否赞成这个方案, 提出方案的海盗也会参与投票, 如果有一半或者以上的海盗赞成, 那么这个方案就通过, 按照这个方案分配金币, 否则这个海盗会被扔进海里喂鲨鱼, 各个海盗都决定聪明并且想使得自己的利益最大化, 当然这里各个海盗首先要能够存活才会考虑使得自己的金币尽量多, 问P(p)编号的海盗最后会获得多少个金币(当有多个可能时输出最少的)


大致思路:

首先当m个海盗按照经典的海盗分金问题进行分配的时候, 如果m个金币够分, 也就是说n <= 2*m的时候, 不会有什么问题, 第n个海盗分得最多的钱, 和Pn间隔为偶数的获得1金币, 其他0金币

那么整个问题变复杂的地方出现在当m个金币不够分的情况也就是当n > 2*m的时候

当n == 2*m + 1的时候, 第n个人只有将所有m个金币分给2*m个人的情形下没有金币的m个人, 每人一金币, 才能活命, 否则某个海盗在让第n个人死的情形下自己的利益没有变化, 那么n的方案就会被反对, 那样反对票回避支持多一票, Pn就死了, 所以Pn为了活命只能给所有Pi(i是奇数)的人分1金币保证自己不死

当n == 2*m + 2的时候, Pn需要把自己的m个金币分给在n == 2*m + 1情形下没有金币的人, 才能加上自己的票保证不死, 那么n == 2*m + 1情形下有m + 1个人没有金币, 也就是说, m个金币给这些人的时候这m + 1个人也都是有可能没有金币的, 所以询问n == 2*m + 2清醒下的每一个人答案都是0

当n == 2*m + 3时, Pn最多将m个金币分给n == 2*m + 2情形下一定拿不到金币的m个人, 那么加上自己一票也只有m + 1票, 提出方案的人一定会死, 其他人就遵循n == 2*m + 2的金币分配作为答案了

当n == 2*m + 4时, P(n - 1)为了活命无论什么分配方案都会支持, 因为到他提方案自己一定会死, 所以此时Pn将金币分给上个n的情形中拿不到金币不会死的m个人(当然满足条件的人不止m个, 所以询问这些人时答案还是0), 加上自己的赞成票, 一共m + 2票通过, Pn在这个情形下不死

n == 2*m + 5时Pn死亡, n == 2*m + 6时Pn死亡, n ==   2*m + 7时Pn死亡, n == 2*m + 8时Pn可以保命, 因为前三个一定要支持他, 不然都会死, 那么加上m票和自己的票一定半数通过

于是可以发现, 只有当n == 2*m + 2^i的时候Pn能保命, 否则就死亡

于是这个题目也就做出来了...


代码如下:

Result  :  Accepted     Memory  :  1584 KB     Time  :  15 ms

/*
 * Author: Gatevin
 * Created Time:  2015/5/13 11:04:52
 * File Name: Rin_Tohsaka.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e)
#define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl

int n, m, p;

int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d %d %d", &n, &m, &p);
        if(n > 2*m)
        {
            if(n == 2*m + 1)
            {
                if(p == n) puts("0");
                else if(p & 1) puts("1");
                else puts("0");
                continue;
            }
            if(__builtin_popcount(n - 2*m) == 1)//是n == 2*m + 2^i的状况
            {
                puts("0");
                continue;
            }
            n -= 2*m;
            int cnt = 30;
            while(((1 << cnt) & n) == 0) cnt--;
            n = (1 << cnt);
            if(p -2*m <= n) puts("0");
            else puts("Thrown");
            continue;
        }
        if(p == n) printf("%d\n", m - (n - 1) / 2);
        else if((n - p) & 1) puts("0");
        else puts("1");
    }
    return 0;
}


你可能感兴趣的:(for,HDU,a,puzzle,Pirates,海盗分金,1538)