塔神的钱包
题目链接:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&contestId=286&id=3544
塔神的钱包
Total Submit: 24 Accepted: 8
Description
台州学院acm集训队有一塔神,人称塔妞,经常以虐xzc取乐,xzc无限愤怒,于是准备在此曝光塔神。其实 ………………………………………………………………………………………………………
塔神是个富二代。
这个不是xzc凭空乱说的,有塔神各种钱包为证,据说塔神money太多,以至于一个钱包放不下,只好分开来放在n个钱包中(您或许会问为什么不存在卡里了,其实我们这里说的money是塔神平时的零花钱),但是钱包太多,塔神平时出去不可能带那么多钱包,于是塔神要合理分配money放在n个钱包中,保证每个钱包都有若干种币值的钱。这样塔神每次出门只要带一个钱包就够了,
或许您要问,这样多麻烦啊,其实呢,塔神也是无奈,因为塔神后宫有MM若干(具体数值不好计算),这些MM也是要零花钱的,据说塔神为了每次临幸完一位MM都会给这位MM零花钱若干,但是身为一个神,塔神是不可能打开一个钱包,再把零花钱给MM的,塔神只会把整个钱包给MM,这些钱包里面的钱都归这个MM了,但是有一点,MM对于每种币值的钱,只能拿一张,每种超过一张的都得还给塔神。塔神好阔气,各种V5。
作为一个神的后宫一员,佳丽对塔神的这种行为表示压力巨大,神的思维不是常人可以理解的。有一次塔神对佳丽说:“这次如果我告诉你每个钱包里钱的种类,你给我计算出你从我手中拿到的money有多少种可能。我就把我的零花钱都奖赏给你。考虑到你的智商,我简化下这个问题,假设我钱包里的钱币值只有14种可能,分别是1、2、3、4、5、10、20、30、50、100、200、500、1000、10000。我现在身上只有400个钱包,并且每个钱包中每种币值的钱都只有一张。”
注意:money总数一样,钱不一样也算不同种可能,比如说一张2元+一张3元,和一张1元+一样4元,算两种情况。
佳丽各种泪奔,跪求各位台州学院的acmer给个OK的程序啊,保证等塔神生气之前求出唯一准确解。解出来的赏佳丽飞吻一个。
Input
有多组数据。输入到文件结束(EOF)
每组数据第一行包含一个整数n(1<=n<=400),.然后下面有n行,代表n个钱包。每行第一个整数k(1<=k<=14)表示该钱包中钱的数量,后面k个整数表示该钱包中的k种钱的币值。输入数据只包含14种币值:1、2、3、4、5、10、20、30、50、100、200、500、1000、10000。
Output
对应每组数据,输出一个整数,表示佳丽能获得的money最多有多少种可能。
Sample Input
2
3 10000 500 20
4 10000 500 20 50
4
1 1
1 10
1 1000
1 10000
Sample Output
2
15
分析:
题意是给出N 个钱包 你可以取1个钱包 2个钱包 …… N个钱包,但是对于多个钱包有相同的面值的话 只能取一张 求能有多少种组合;(对于总价值 5 = 1 + 4, 5 = 2 + 3算2种情况)。
一共最多有14种面值,那么可以把一个钱包想成一个14位的2进制数,组成的最大数也就是 (2^14 -1);
对于第一组数据
2
3 10000 500 20 -> 10100001000000; +1
4 10000 500 20 50 -> 10100101000000; +1
第一个钱包 和 第二个钱包 组合 就是10100001000000 | 10100101000000 = 10100101000000;同于第二个钱包,
所以total = 2;
那么就是对状态进行或运算的母函数,每个钱包和每个状态或运算组合下
时间复杂度O(n*(2^14-1))
代码:
View Code #include<iostream>
using namespace std;
const int MAXN=1<<15;
int main()
{
// freopen("data1.out", "w", stdout);
int T,n;
int a[MAXN]; //表示每个钱包
int m[]={1,2,3,4,5,10,20,30,50,100,200,500,1000,10000};
while (cin>>T)
{
int i,j,k,tmp;
memset(a, 0, sizeof(a));
for (i=0; i<T; i++)
{
cin>>n;
for (k=0; k<n; k++)
{
cin>>tmp;
for (j=0; j<14; j++) //用二进制表示每个钱包的状态
{
if (m[j]==tmp)
{
a[i] |= (1<<j);
break;
}
}
}
}
bool c1[MAXN], c2[MAXN];
memset(c1, false, sizeof(c1));
memset(c2, false, sizeof(c2));
for(i = 0; i < T; i++) //初始化每个钱包的状态,令每个钱包的状态都为true
{
c1[a[i]] = true;
}
int maxn=(1<<14)-1; //不能写成1<<14-1,这个相当于1<<13;
for(i = 0; i < T; i++) //计算钱包的每种组合可能,令每种可能都为true
{
for(j = 1; j <= maxn; j++)
{
c2[(j|a[i])] |= c1[j];
}
for(j = 1; j <= maxn; j++)
{
c1[j] |= c2[j];
c2[j] = false;
}
}
int sum=0;
for (i=0; i<=maxn; i++)
{
if (c1[i]) sum++;
}
cout<<sum<<endl;
}
return 0;
}

浙公网安备 33010602011771号