[BZOJ 1028][JSOI 2007] 麻将 模拟+贪心思想
2017-10-25 20:57
295 查看
题目传送门:【BZOJ 1028】
题目大意: 这里,我们考虑一种特殊的麻将。在这种特殊的麻将里,没有字牌,花色也只有一种。但是,序数不会被限制在 1 到 9 的范围内,而是在 1 到 n 的范围内。同时,也没有每一种牌恰好四张的限制。一组和了的牌由 3m + 2 张牌组成,其中两张组成对子,其余 3m 张组成三张一组的 m 组牌,每组须为顺子(连续的三张牌)或刻子(相同的三张牌)。现给出一组 3m + 1 张的牌,要求判断该组牌是否为听牌(即还差一张牌就可以和牌)。如果是的话,按顺序从小到大输出所有可能的等待牌,否则输出 NO。(9 ≤ n ≤ 400,4 ≤ m ≤ 1000 )
题目分析:
不明白为什么省选题还只有这个难度……
由题,这道题数据规模仅为 n ≤ 400,因此 O(n3) 的暴力算法也可以轻松跑过。所以我们直接上模拟即可。
大体思路:我们要遵循“模拟每次要从最简单的地方上手”的原则,于是我们在按顺序枚举 1-n 之内的数是否为听牌序号时,先依次判断 1-n 内的对子;如果此时有任意一种牌的数量 ≥3, 我们就先把多余的牌当作刻子打出,最后再考虑顺子的情况,如果有负数出现说明不合法。
注意每次要考虑 n+1,n+2 是否为负数;在开始新的枚举时,一定要把原来的记录给抹掉。
下面附上代码:
[cpp] view plain copy print?#include<cstdio>
#include<cstring>
const int MX=405;
int n,m,totm,q[MX],tl=0;
int cnt[MX],tmp[MX];
bool check(int x){
for (int i=1;i<=n;i++){ //枚举最后剩下的对子
bool ok=true;
memcpy(tmp,cnt,sizeof(int)*(n+5));
tmp[x]++;
if (tmp[i]>=2){
tmp[i]-=2;
for (int j=1;j<=n+2;j++){ //检验当前牌的状态
if (tmp[j]<0){
ok=false;
break;
}
if (tmp[j]%=3){ //优先打出刻子
tmp[j+1]-=tmp[j],tmp[j+2]-=tmp[j];
tmp[j]=0;
}
}
if (ok)
return true;
}
}
return false;
}
int main(){
int a;
scanf(”%d%d”,&n,&m);
for (int i=1;i<=3*m+1;i++){
scanf(”%d”,&a);
cnt[a]++;
}
for (int i=1;i<=n;i++){ //判断听牌为 i 时是否有解
if (check(i))
q[++tl]=i;
}
if (tl==0) printf(“NO”);
else {
for (int i=1;i<tl;i++) printf(“%d ”,q[i]);
printf(”%d”,q[tl]);
}
return 0;
}
题目大意: 这里,我们考虑一种特殊的麻将。在这种特殊的麻将里,没有字牌,花色也只有一种。但是,序数不会被限制在 1 到 9 的范围内,而是在 1 到 n 的范围内。同时,也没有每一种牌恰好四张的限制。一组和了的牌由 3m + 2 张牌组成,其中两张组成对子,其余 3m 张组成三张一组的 m 组牌,每组须为顺子(连续的三张牌)或刻子(相同的三张牌)。现给出一组 3m + 1 张的牌,要求判断该组牌是否为听牌(即还差一张牌就可以和牌)。如果是的话,按顺序从小到大输出所有可能的等待牌,否则输出 NO。(9 ≤ n ≤ 400,4 ≤ m ≤ 1000 )
题目分析:
不明白为什么省选题还只有这个难度……
由题,这道题数据规模仅为 n ≤ 400,因此 O(n3) 的暴力算法也可以轻松跑过。所以我们直接上模拟即可。
大体思路:我们要遵循“模拟每次要从最简单的地方上手”的原则,于是我们在按顺序枚举 1-n 之内的数是否为听牌序号时,先依次判断 1-n 内的对子;如果此时有任意一种牌的数量 ≥3, 我们就先把多余的牌当作刻子打出,最后再考虑顺子的情况,如果有负数出现说明不合法。
注意每次要考虑 n+1,n+2 是否为负数;在开始新的枚举时,一定要把原来的记录给抹掉。
下面附上代码:
[cpp] view plain copy print?#include<cstdio>
#include<cstring>
const int MX=405;
int n,m,totm,q[MX],tl=0;
int cnt[MX],tmp[MX];
bool check(int x){
for (int i=1;i<=n;i++){ //枚举最后剩下的对子
bool ok=true;
memcpy(tmp,cnt,sizeof(int)*(n+5));
tmp[x]++;
if (tmp[i]>=2){
tmp[i]-=2;
for (int j=1;j<=n+2;j++){ //检验当前牌的状态
if (tmp[j]<0){
ok=false;
break;
}
if (tmp[j]%=3){ //优先打出刻子
tmp[j+1]-=tmp[j],tmp[j+2]-=tmp[j];
tmp[j]=0;
}
}
if (ok)
return true;
}
}
return false;
}
int main(){
int a;
scanf(”%d%d”,&n,&m);
for (int i=1;i<=3*m+1;i++){
scanf(”%d”,&a);
cnt[a]++;
}
for (int i=1;i<=n;i++){ //判断听牌为 i 时是否有解
if (check(i))
q[++tl]=i;
}
if (tl==0) printf(“NO”);
else {
for (int i=1;i<tl;i++) printf(“%d ”,q[i]);
printf(”%d”,q[tl]);
}
return 0;
}
相关文章推荐
- BZOJ_1028_[JSOI2007]_麻将_(模拟+贪心)
- BZOJ.1028.[JSOI2007]麻将(贪心)
- [BZOJ1028][JSOI2007]麻将(模拟)
- [BZOJ1028][JSOI2007]麻将(贪心)
- [bzoj1028][JSOI2007]麻将【暴力】【贪心】
- bzoj 1028: [JSOI2007]麻将 (贪心)
- bzoj1028 [JSOI2007]麻将(暴力枚举+贪心)
- 【BZOJ】1028: [JSOI2007]麻将(贪心+暴力)
- [BZOJ 1028] [JSOI2007] 麻将 【枚举+贪心判断】
- BZOJ 1028 JSOI 2007 麻将 贪心
- BZOJ1028[JS0I2007] 麻将 解题报告【模拟+贪心(?)】
- BZOJ1029: [JSOI2007]建筑抢修[模拟 贪心 优先队列]
- BZOJ1028【JSOI2007】麻将
- bzoj1028 [JSOI2007]麻将
- 【bzoj1028】[JSOI2007]麻将
- 【BZOJ1028】【JSOI2007】麻将 暴力
- bzoj1028 [JSOI2007]麻将
- 【BZOJ 1028】【 JSOI2007】麻将
- 【bzoj1028】[JSOI2007]麻将
- bzoj1028 [JSOI2007]麻将