UVALive 5907 —— Tichu(搜索)
来源:互联网 发布:达内培训 武汉java 编辑:程序博客网 时间:2024/05/17 00:05
题目在此
题意:前面废话忽略,重点是,手上初始有13张牌(输入),然后按照一定的规则可以将牌组合起来,每张牌必须且只能用一次;
问题是要找一种方案使得组合出来的组数应尽量少,输出最少多少组,并输出任意一个方案。
每张牌上面有点数2~9 T J Q K A,规定点数按照这个顺序增大,即2是最小, A是最大的,花色用s,h,c,d代表;
题目给出6种组合规则:
1、单一张牌;
2、两张点数一样的牌;
3、三张点数一样的牌;
4、四张点数一样的牌;
5、三张点数为x和两站点数为y,x和y不同,当然相同你也找不到5张。。。
6、点数连续至少5张,如6789TJ,其实就是按照上面的点数大小顺序来;
题目保证输入的牌不会有重复。
采用搜索来解这个题目,貌似不用怎么剪枝速度也是很快的。
看起来有13张牌,逐张搜索的话每层理论是6种决策,也就是总状态数6^13,但事实上并不会出现这么多。因为你每次组合都会引发其他牌数量的减少,也就是说其实收敛得很快的,像规则5和6一次至少都去掉5张牌了。
我的做法是用一个数组f记录每种点数的张数,再用一个布尔的数组p,p[i][j]为1代表点数为i的牌出现了第j种花色(这个是为了后面输出方案)。
点数方面,为了后面枚举方便,将上面的点数按顺序映射到0~12,点数2在0位置,A在12位置,下面说到的点数都是位置了。
上面看上去是6种方案,实际可以把前四点看作一种:对于点数x,枚举取1~f[x]张牌。
单种点数的枚举和三飞二的没什么,主要是连续的枚举,假如有0~11都可以连续得到,如果先枚举0~4,接着0~5,0~6等等,个人觉得是比较麻烦了。
我的做法是直接用i从x往右扫,直到i==13或是f[i]为0,break出来,那么说明x最多连续到i-1,前面在扫的时候对那些非0都先减一;
接下来就从x~i往回枚举了,如果i-x<4就说明不足5张,不用递归,否则就递归下去,递归完了,要判断x~i-1了,此时先将f[i]++,因为现在是不取i了。(可能有点绕,看代码可能好懂些)
在搜索的时候,每次选择一种决策方案的时候,先把选择的点数做对应的修改(减少),花色不用管,决策没管到花色,然后递归进入下一层,回溯的时候在把点数加回去即可。
方案的记录,我是采用一个结构体
struct Solu{ int A, B, C; Solu(){} Solu(int _A, int _B, int _C){ A=_A; B=_B; C=_C; }}
A代表方案类型,具体如下:
A=0时:表示连续的B到C,比如6789TJ,就表示为A=0,B=4,C=9(这里记录的还是点数映射的位置)
A=1时:表示点数为B取了C张;
A=2时:表示点数为B取了三张,点数C的取了两张;
然后剩下的工作就是写好搜索函数,寻找并记录最优答案了。
最后面的输出,就通过分析结构体内A的类型做对应的输出即可。因为题目对方案的顺序没要求,所以你就随意咯,怎么输出方便就怎么来。
具体细节请参考代码:
#include<cstdio>#include<cstring>const int inf = 0x7fffffff;char s[10];char list[20]={'2','3','4','5','6','7','8','9','T','J','Q','K','A'};char type[10]={'s','h','c','d'};void getch(char a, char b, int& x, int& y){ for(int i=0; i<13; i++){ if(list[i]==a){ x=i; break; } } for(int i=0; i<4; i++){ if(type[i]==b){ y=i; break; } }}int f[13];bool p[13][4];void print(int x){ putchar(list[x]); //选择一个存在的花色输出,并把花色标记为0 for(int i=0; i<4; i++){ if(p[x][i]){ putchar(type[i]); p[x][i]=0; break; } }}struct Solu{ int A, B, C; Solu(){} Solu(int _A, int _B, int _C){ A=_A; B=_B; C=_C; }}cur[50], res[50];//cur记录当前的方案,res记录当前的最优方案int t, ans;void dfs(int x, int u){ if(u>=ans) return;//小小的剪枝,如果当前组数超过全局最优则返回 if(x>=13){ if(u<ans){//更新答案 ans = u; for(int i=0; i<u; i++) res[i] = cur[i]; } return; } //当前点数张数为0,直接看下一个点数 //并且这样的写法,保证了搜索到x时,x前面的点数一定是空的或是被取完了 if(!f[x]){ dfs(x+1, u); return; } int i; //找向右的连续最大区间 for(i=x; i<13; i++){ if(!f[i]) break; f[i]--; } for(--i; i>=x; i--){ if(i-x>=4){//连续超过5张的 cur[u] = Solu(0, x, i); dfs(x, u+1); } f[i]++; } for(i=1; i<=f[x]; i++){ //同种点数取i张 f[x]-=i; cur[u] = Solu(1, x, i); dfs(x, u+1); f[x]+=i; } if(f[x]>=3){ //取三张x和两张i f[x]-=3; for(i=x+1; i<13; i++){ if(f[i]>=2){ f[i]-=2; cur[u] = Solu(2, x, i); dfs(x, u+1); f[i]+=2; } } f[x]+=3; } if(f[x]>=2){ //取三张i和两张x f[x]-=2; for(i=x+1; i<13; i++){ if(f[i]>=3){ f[i]-=3; cur[u] = Solu(2, i, x); dfs(x, u+1); f[i]+=3; } } f[x]+=2; }}int main(){ scanf("%d", &t); while(t--){ int x, y; memset(f,0,sizeof(f)); memset(p,0,sizeof(p)); for(int i=0; i<13; i++){ scanf("%s", s); getch(s[0], s[1], x, y); f[x]++; p[x][y]=1; } ans = inf; dfs(0,0); printf("%d\n", ans); for(int i=0; i<ans; i++){ if(res[i].A==0){ for(int j=res[i].B; j<=res[i].C; j++){ if(j!=res[i].B) putchar(' '); print(j); } } else if(res[i].A==1){ for(int j=0; j<res[i].C; j++){ if(j) putchar(' '); print(res[i].B); } } else{ print(res[i].B); for(int j=0; j<2; j++){ putchar(' '); print(res[i].B); putchar(' '); print(res[i].C); } } puts(""); } } return 0;}
- UVALive 5907 —— Tichu(搜索)
- UVALive 6432 —— Influence(记忆化搜索 + 状态压缩)
- uvalive 3635 - Pie(二分搜索)
- uvalive 3971 - Assemble(二分搜索 + 贪心)
- uvalive 3971 - Assemble(二分搜索 + 贪心)
- uvalive 3635 - Pie(二分搜索)
- UVALive 6953Digi Comp II(搜索)
- UVALive 3667 Ruler(回溯搜索)
- UVALive 6902Three Squares(二分 + 搜索)
- UVALive 3565 Bit Compressor (搜索)
- 【UVALive 7364】Robots(逆向思维+搜索)
- UVALive 4877 记忆搜索
- UVALive 6430 —— Points(DP)
- UVALive 3710 Interconnect(记忆化搜索 + hash)
- UVALive 5833 Moles(笛卡尔树+搜索+hash)
- UVaLive/LA 6809 Spokes Wheel(搜索,二进制循环移位)
- UVALive 7416 Bringing Order to Disorder(搜索)
- UVALive 4050 Hanoi Towers(记忆化搜索)
- 第64天
- 32路舵机控制器用法
- Stringstream 缓冲区清空方法 和 复用StringStream 不是clear那么简单
- hdu_1201 18岁生日
- 庄伟雄:基于移动互联网的供应链管理
- UVALive 5907 —— Tichu(搜索)
- 弹出窗口,并适合屏幕大小
- 负载均衡的基本(常用)算法
- error: conflicting type qualifiers for 'xxxxx'
- 套接字设置超时总结
- Float类的floatToIntBit方法
- 深入理解 GCD(一)
- 4.使用Jackson将Json数据转换成实体数据
- assertion failed: Path for IClasspathEntry must be absolute解决方法