标签:lin hat ssi hide chinese ike 压缩 table field
题目传送门:http://poj.org/problem?id=1632
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 2308 | Accepted: 901 |
Sample Input
2 5 11 13 23 5 17 36 11 5 23 13 2 23 15 15 23
Sample Output
2 1
Source
N个瓶子,每个瓶子有两种属性 形状 和 颜色,我们要找到最大 K, 使得K*K个瓶子 都是由 K种 形状和颜色组成。
不是很好理解...
另一种理解可以把shape和decoration看成点,它们之际的对应关系看成边,这样就得到两个集合的映射。用A表示shape的集合,B表示decoration的集合。题目要求的就是原图的一个最大子图:使得该子图也可以分为A的子集A’和B的子集B’两部分,且从A’的每个点出发,到B’的任意点都存在边。
参考:https://blog.csdn.net/sj13051180/article/details/6612732
呃...我觉得这道题最大的难点在于理解题意了,看题目看到怀疑人生。
题意搞懂之后很容易想到状态压缩,之前搞状态压缩都在DP上搞,这次搬到搜索上有意思。
我们不妨设一个数组 Cp[ x ] = y; x(数组下标)表示shape, 数值 y 表示decoratio;y 最大可以到达 2^36, 所以数组定义个 long long 即可。 (有点像浓缩版的vector)
接下来就是暴力深搜去匹配了,两两匹配,如果匹配成功则两个合并后继续匹配(试试能否继续壮大),如果匹配失败则分道扬镳(各自寻找属于自己的那群小伙伴),不断匹配去寻找K的最大值。
AC code(116k 0ms):
1 //DFS 状态压缩 2 #include <cstdio> 3 #include <cmath> 4 #include <cstring> 5 #include <iostream> 6 #include <algorithm> 7 #define ll long long int 8 using namespace std; 9 10 const int MAXN = 50; 11 ll Cp[MAXN]; 12 int N, ans; 13 14 int cmp(ll num) 15 { 16 int cnt = 0; 17 while(num) 18 { 19 cnt+=(num&1); 20 num>>=1; 21 } 22 return cnt; 23 } 24 void dfs(int k, int st, ll tp) ///花瓶数 当前花瓶编号 当前累积的颜色值 25 { 26 if(k > ans) ans = k; 27 for(int i = st; i <= 36; i++) 28 { 29 if(cmp(Cp[i]&tp) > k) 30 dfs(k+1, i+1, (Cp[i]&tp)); 31 } 32 } 33 int main() 34 { 35 int T, u, v; 36 scanf("%d", &T); 37 while(T--) 38 { 39 memset(Cp, 0, sizeof(Cp)); 40 ans = 0; 41 scanf("%d", &N); 42 for(int i = 0; i < N; i++) 43 { 44 scanf("%d%d", &u, &v); 45 Cp[u]|=(1ll<<v); 46 } 47 dfs(0, 1, (1ll>>36)-1); 48 printf("%d\n", ans); 49 } 50 return 0; 51 }
POJ 1632 Vase collection【状态压缩+搜索】
标签:lin hat ssi hide chinese ike 压缩 table field
原文地址:https://www.cnblogs.com/ymzjj/p/9499543.html