傳送門:http://poj.org/problem?id=3139
題目大意:給出16個不大於1024數,每個數只使用一次,求使得下列等式成立的方案數。
x1 * 4 + x2 * 3 + x3 * 2 + x4 = x5 + x6 * 2 + x7 * 3 + x8 * 4
y1 * 4 + y2 * 3 + y3 * 2 + y4 = y5 + y6 * 2 + y7 * 3 + y8 * 4
思路:G[x]記錄的是能夠組成和爲x的四個數的集合(壓縮成一個數表示),枚舉四個數的全排列,算出tmp=bit[1]+bit[2]*2+bit[3]*3+bit[3]*4,然後找之前已經求過的也能湊成tmp的四個數的組合,若兩者沒有重複元素,則可以組成一組無重複的8個數的等式,這裏問題就解決了一半了,這時候就可以把能夠使等式滿足的8個數的每種組合的方案數都求出來,放在state[x]裏面保存,最後枚舉一遍(0,1<<16),把無重複的兩組8個數的組合的方案數相乘後(state[i]*state[((1<<16)-1)^i])累加到ans,由於枚舉時候正反會重複,所以最後ans/2就是總共16個數使等式成立的方案數。
感想:位運算和狀態壓縮可以簡化枚舉的策略,也有許多意想不到的方便。
Code:
/* W w w mm mm 222222222 7777777777777 */
/* W w w w m m m m 222 22 7777 */
/* w w w w m m m m 22 777 */
/* w w w w m m m m 22 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* ww ww m mm m 222222222222222 77 */
//#pragma comment(linker, "/STACK:102400000,102400000")
//C++
//int size = 256 << 20; // 256MB
//char *p = (char*)malloc(size) + size;
//__asm__("movl %0, %%esp\n" :: "r"(p));
//G++
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<ctime>
#include<deque>
#include<cmath>
#include<vector>
#include<string>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
#define REP(i,s,t) for(int i=(s);i<=(t);i++)
#define REP2(i,t,s) for(int i=(t);i>=s;i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned long ul;
const int N=20;
const int Maxans=10240+10;
int a[N];
int bit[N];
vector<int>G[Maxans];
int state[1<<17];
bool judge(int x)
{
int cnt=0;
REP(i,1,16)
{
if(x&(1<<(i-1)))
{
bit[++cnt]=a[i];
}
}
return cnt==4;
}
int fuck()
{
REP(i,0,Maxans)
{
G[i].clear();
}
memset(state,0,sizeof(state));
sort(a+1,a+1+16);
REP(i,0,(1<<16)-1)
{
if(judge(i))
{
do
{
int tmp=bit[1]*1+bit[2]*2+bit[3]*3+bit[4]*4;
for(int j=0;j<G[tmp].size();j++)
{
if((i&G[tmp][j])==0)
{
state[i|G[tmp][j]]++;
}
}
G[tmp].push_back(i);
}while(next_permutation(bit+1,bit+1+4));
}
}
int ans=0;
REP(i,0,(1<<16)-1)
{
ans+=state[i]*state[((1<<16)-1)^i];
}
return ans/2;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("test.in","r",stdin);
#endif
int ca=1;
while(~scanf("%d",&a[1]))
{
if(!a[1])
{
break;
}
REP(i,2,16)
{
scanf("%d",&a[i]);
}
int ans=fuck();
printf("Case %d: %d\n",ca++,ans);
}
return 0;
}