斗地主是偏题
我真是醉了这道题
还是没搞清楚能不能四带四。。(四可以拆成俩对对子。。)
还有四带二能不能带王炸。。。
题意不清啊。。
最后看标程发现可以带王炸不能带四。。
bi了哈士奇了为什么可以带王炸却不能带俩个一样的对子。。
因为纠结这些个东西去年跪在这里没去打所以只拿了20还是30?
其实是一道搜索。。讲明白还是不难的。。
记得把尖刀(A)标为14,因为它可以连在王(King)后面
每一种状态先看看不出连牌要几次
先把四带二出完,再出三带一,最后加上单牌和对,记录并更新ans
然后枚举连牌并继续向下搜索
实现起来也是不难的,也不长。。加上读入/输出优化才七十几行
#include<bits/stdc++.h>
#define g getchar()
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
inline ll read(){
ll x=0,f=1;char ch=g;
for(;ch<'0'||ch>'9';ch=g)if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=g)x=x*10+ch-'0';
return x*f;
}
inline void out(ll x){
int a[25],wei=0;
if(x<0)putchar('-'),x=-x;
for(;x;x/=10)a[++wei]=x%10;
if(wei==0){puts("0");return;}
for(int j=wei;j>=1;--j)putchar('0'+a[j]);
putchar('\n');
}
int ans,T,n;
int cnt[5],hand[16];
void dfs(int x){
if(x>ans)return;
int rest=0;
memset(cnt,0,sizeof(cnt));
for(int i=0;i<15;++i)cnt[hand[i]]++;
for(;cnt[4];){
cnt[4]--,rest++; //炸弹
if(cnt[2]>=2)cnt[2]-=2; //能不能带二
else if(cnt[1]>=2)cnt[1]-=2;
}
for(;cnt[3];){
cnt[3]--,rest++; //三张牌
if(cnt[2])cnt[2]--; //能不能带一
else if(cnt[1])cnt[1]--;
} //我在思考把三带一和四带二写成子程序是不是更简洁?
if(hand[0]&&hand[1]&&cnt[1]>=2)--rest; //看看剩下的单牌有没有王炸
rest+=cnt[1]+cnt[2];
ans=min(rest+x,ans);
for(int i=3,j;i<15;++i){ //单顺子
for(j=i;hand[j]&&j<15;++j){
hand[j]--;if(j-i+1>=5)dfs(x+1); //如果多于5张向下搜索
}
for(;j>i;)hand[--j]++;
}
for(int i=3,j;i<=15;++i){ //双顺子
for(j=i;hand[j]>=2&&j<15;++j){
hand[j]-=2;if(j-i+1>=3)dfs(x+1);
}
for(;j>i;)hand[--j]+=2;
}
for(int i=3,j;i<=15;++i){ //三顺子
for(j=i;hand[j]>=3&&j<15;++j){
hand[j]-=3;if(j-i+1>=2)dfs(x+1);
}
for(;j>i;)hand[--j]+=3;
} //我在思考是不是把顺子什么写个子程序会更简洁?
}
int main(){
T=read();n=read();
for(;T--;){
ans=n;
memset(hand,0,sizeof(hand));
for(int i=1;i<=n;++i){
int x=read(),y=read();
if(x==0)hand[y-1]++; //Joker要分开存,因为它们并不能组成对牌
else if(x==1)hand[14]++;
else hand[x]++;
}
dfs(0);out(ans);
}
return 0;
}
发现一个人程序写错然而AC了让我很难过,而且UO(钩)的斗地主因为数据是随机的所以不能Hack。。