hdu 1557 权利指数 ( 二进制枚举子集) 解题心得

原题:

Description

在选举问题中,总共有n个小团体,每个小团体拥有一定数量的选票数。如果其中m个小团体的票数和超过总票数的一半,则此组合为“获胜联盟”。n个团体可形成若干个获胜联盟。一个小团体要成为一个“关键加入者”的条件是:在其所在的获胜联盟中,如果缺少了这个小团体的加入,则此联盟不能成为获胜联盟。一个小团体的权利指数是指:一个小团体在所有获胜联盟中成为“关键加入者”的次数。请你计算每个小团体的权利指数。
 

Input

输入数据的第一行为一个正整数T,表示有T组测试数据。每一组测试数据的第一行为一个正整数n(0<n<=20)。第二行有n个正整数,分别表示1到n号小团体的票数。
 

Output

对每组测试数据,在同一个行按顺序输出1到n号小团体的权利指数。
 

Sample Input

2 1 10 7 5 7 4 8 6 7 5
 

Sample Output

1 16 22 16 24 20 22 16
 
 分析:n位二进制数,每个都有不同状态1,0,所以可以表示2^n种不同情况,具体实现方法是 ,tp&1   的结果为tp的最后一位是不是1,是1返回真,
否则返回假,之后再每次将tp>>1.这样就可以逐位判断了 
 
 
我的代码:
#include <iostream>
using namespace std;

int main()
{
    int t, n, a[25], i, key[25], k, total, ans[25];
    scanf("%d", &t);
    while (t--)
    {
        memset(ans, 0, sizeof(ans));
        total = 0;
        scanf("%d", &n);
        for (i = 0; i < n; i++)
            scanf("%d", a + i), total += a[i];
        total /= 2;    //总票数的一半【写成total = (total+1)/2 会错……】
        //枚举子集【1】~【2的n次方-1】
        int maxs = 1 << 3;
        cout <<"maxs="<< maxs << endl;
        int flag = 0;
        for (i = 1; i < maxs; i++)
        {
            cout << flag++ << endl;
            k = 0;
            int tp = i, j = 0, sum = 0;
            while (tp)
            {
                //cout <<"tp="<<tp<<"       "<< (tp & 1) << endl;
                if (tp & 1)//tp的二进制从左往右数第j位是1,则认为a[j]入了集合
                    key[k++] = j, sum += a[j];
                //记住入了集合的a的元素编号j,并累加票数
                tp >>= 1;    //tp的二进制往右移动,即消去二进制最后一位
                j++;
            }
            if (sum > total)    //如果团体的票数超过总票数的一半
            for (j = 0; j < k; j++)
            if (sum - a[key[j]] <= total)
                ans[key[j]]++;
            //如果没了a[key[j]]就不行,则编号为key[j]的元素为“关键加入者”,该元素权利指数+1
        }
            printf("%d", ans[0]);
        for (i = 1; i < n; i++)
            printf(" %d", ans[i]);
        printf("\n");
    }
    return 0;
}
View Code

 

posted @ 2015-08-02 20:29  Shawn_Ji  阅读(937)  评论(0编辑  收藏  举报