华师一附中OI组
标题:
P2668 斗地主
[打印本页]
作者:
admin
时间:
2018-5-11 11:16
标题:
P2668 斗地主
https://www.luogu.org/problemnew/show/P2668
题目描述
牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关 系根据牌的数码表示如下: 3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王 ,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由 nn 张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。
现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。
需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。具体规则如下:
本题数据随机,不支持hack,要hack或强力数据请点击这里
输入输出格式
输入格式:
第一行包含用空格隔开的2个正整数 T,nT,n ,表示手牌的组数以及每组手牌的张数。
接下来 TT 组数据,每组数据 nn 行,每行一个非负整数对 a_i,b_ia ,表示一张牌,其中 a_ia表示牌的数码, b_ib表示牌的花色,中间用空格隔开。特别的,我们用 11 来表示数码 A, 1111 表示数码 J, 1212 表示数码 Q, 1313 表示数码 K;黑桃、红心、梅花、方片分别用 1-4 来表示;小王的表示方法为 0 1 ,大王的表示方法为 0 2 。
输出格式:
共 TT 行,每行一个整数,表示打光第 ii 组手牌的最少次数。
输入输出样例
输入样例#1:
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
输出样例#1:
3
输入样例#2:
1 17
12 3
4 3
2 3
5 4
10 2
3 3
12 2
0 1
1 3
10 1
6 2
12 1
11 3
5 2
12 4
2 2
7 2
输出样例#2:
6
说明
样例1说明
共有1组手牌,包含8张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方片A以及黑桃A。可以通过打单顺子(方片7,方片8,黑桃9,方片10,黑桃J),单张牌(黑桃5)以及对子牌(黑桃A以及方片A)在3次内打光。
对于不同的测试点, 我们约定手牌组数T与张数n的规模如下:
数据保证:所有的手牌都是随机生成的。
作者:
lyc
时间:
2018-7-4 16:58
一开始直接搜索tle,后来看题解说搜索顺子,散牌贪心打出来,没考虑拆牌打,不过随机数据弱……
这种题打得真的累……
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int N = 20;
using namespace std;
int p[N],c[N];
int n,t,ans;
int other()
{
memset(c,0,sizeof(c));
for(int i=0; i<=13; i++)
c[p[i]]++;
int t=0;
while(c[4] && c[2]>1)
c[4]--, c[2]-=2, t++;
while(c[4] && c[1]>1)
c[4]--, c[1]-=2, t++;
while(c[4] && c[2])
c[4]--, c[2]--, t++;
while(c[3] && c[2])
c[3]--, c[2]--, t++;
while(c[3] && c[1])
c[3]--, c[1]--, t++;
return t + c[1] + c[2] + c[3] + c[4];
}
void dfs(int now)
{
if(now >= ans)
return ;
int add = other();
if(now + add < ans)
ans = now + add;
for(int i=2; i<=13; i++)
{
int j=i;
while(p[j] >= 3)
j++;
if(j-i >= 2)
{
for(int m=i+1; m<=j-1; m++)
{
for(int k=i; k<=m; k++)
p[k]-=3;
dfs(now+1);
for(int k=i; k<=m; k++)
p[k]+=3;
}
}
}
for(int i=2; i<=13; i++)
{
int j=i;
while(p[j]>=2)
j++;
if(j-i>=3)
{
for(int m=i+2; m<=j-1; m++)
{
for(int k=i; k<=m; k++)
p[k]-=2;
dfs(now+1);
for(int k=i; k<=m; k++)
p[k]+=2;
}
}
}
for(int i=2; i<=13; i++)
{
int j=i;
while(p[j]>=1)
j++;
if(j-i>=3)
{
for(int m=i+4; m<=j-1; m++)
{
for(int k=i; k<=m; k++)
p[k]--;
dfs(now+1);
for(int k=i; k<=m; k++)
p[k]++;
}
}
}
}
int main()
{
cin>>t>>n;
while(t--)
{
memset(p,0,sizeof(p));
for(int i=1; i<=n; i++)
{
int a, b;
cin>>a>>b;
if(a==1)
a=13;
else if(a)
a--;
p[a]++;
}
ans=n;
dfs(0);
cout<<ans<<endl;
}
return 0;
}
复制代码
作者:
admin
时间:
2018-7-4 17:25
好牛! 此题很锻炼你们的手上的功夫
作者:
lyc
时间:
2018-7-4 18:06
本帖最后由 lyc 于 2018-7-4 18:08 编辑
加强版数据太强了……疯狂特判(因为还有可以拆的牌,不过整体还是一样,改一下散牌)然而我之前漏了好多,,,debug好久,部分特判参考题解
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int N = 20;
using namespace std;
int p[N],c[N];
int n,t,ans;
int other(){//打散牌
int t = 0;
int c[10]; bool boom = 0;//炸弹
memset(c, 0, sizeof(c));
if(p[0] == 2) boom = 1;
c[1] += p[0];//王分开算
for(int i=1; i<=13; i++) c[p[i]] ++;
while(!c[3] && c[4] >= 2 && c[1] == 1 && c[2] == 1) c[4]-=2, c[1] --, c[2] --, t += 2;
while(!c[3] && c[4] >= 2 && c[1] == 2 && c[2] == 2) c[4]-=2, c[1] -=2, c[2] -=2, t += 2;
while(!c[2] && c[3] >= 2 && c[4] == 1 && c[1] == 1) c[3]-=2, c[1] --, c[4] --, t += 2;
if(c[3] + c[4] > c[1] + c[2])
while(c[4] && c[2] && c[3]) c[2]--, c[3]--, c[1]++, c[4]--,t++;
if(c[3] + c[4] > c[1] + c[2])
while(c[4] && c[1] && c[3]) c[1]--, c[3]--, c[2]++, c[4]--,t++;//以上拆牌打更优
if(c[3] % 3 == 0 && c[1] + c[2] <= 1)//拆三张
while(c[3] > 2) c[3] -= 3, t += 2;
while(c[4] && c[2] >= 2) c[4] --, c[2] -= 2, t++;//四带二对
while(c[4] && c[1] >= 2) c[4] --, c[1] -= 2, t++;//四带二
while(c[4] && c[2] >= 1) c[4] --, c[2] -- , t++;//四带一对
while(c[3] && c[2]) c[3] --, c[2] --, t++;
while(c[3] && c[1]) c[3] --, c[1] --, t++;
while(c[4] >= 2 && c[3]) c[4] -= 2, c[3] --, t+=2;
while(c[3] >= 2 && c[4]) c[3] -= 2, c[4] --, t+=2;//拆三和炸弹
while(c[3] >= 3) c[3] -= 3, t+=2;//三张三也能拆orz
while(c[4] >= 2) c[4]-=2, t++;
if(boom && c[1] >= 2) return t + c[1] + c[2] + c[3] + c[4] - 1;
return t + c[1] + c[2] + c[3] + c[4];
}
void dfs(int now)
{
if(now >= ans)
return ;
int add = other();
if(now + add < ans)
ans = now + add;
for(int i=2; i<=13; i++)
{
int j=i;
while(p[j] >= 3)
j++;
if(j-i >= 2)
{
for(int m=i+1; m<=j-1; m++)
{
for(int k=i; k<=m; k++)
p[k]-=3;
dfs(now+1);
for(int k=i; k<=m; k++)
p[k]+=3;
}
}
}
for(int i=2; i<=13; i++)
{
int j=i;
while(p[j]>=2)
j++;
if(j-i>=3)
{
for(int m=i+2; m<=j-1; m++)
{
for(int k=i; k<=m; k++)
p[k]-=2;
dfs(now+1);
for(int k=i; k<=m; k++)
p[k]+=2;
}
}
}
for(int i=2; i<=13; i++)
{
int j=i;
while(p[j]>=1)
j++;
if(j-i>=3)
{
for(int m=i+4; m<=j-1; m++)
{
for(int k=i; k<=m; k++)
p[k]--;
dfs(now+1);
for(int k=i; k<=m; k++)
p[k]++;
}
}
}
}
int main()
{
cin>>t>>n;
while(t--)
{
memset(p,0,sizeof(p));
for(int i=1; i<=n; i++)
{
int a, b;
cin>>a>>b;
if(a==1)
a=13;
else if(a)
a--;
p[a]++;
}
ans=n;
dfs(0);
cout<<ans<<endl;
}
return 0;
}
复制代码
作者:
杜文骞
时间:
2020-1-16 11:43
#include<bits/stdc++.h>
using namespace std;
int t,n,x,y,ans;
int sum[25];
int ans2[25];
void dfs(int v)
{
if(v>=ans)return;
int k=0;
for(int i=3;i<=14;i++)
{
if(sum[i]==0)k=0;
else
{
k++;
if(k>=5)
{
for(int j=i;j>=i-k+1;j--)
{
sum[j]--;
}
dfs(v+1);
for(int j=i;j>=i-k+1;j--)
{
sum[j]++;
}
}
}
}
k=0;
for(int i=3;i<=14;i++)
{
if(sum[i]<=1)k=0;
else
{
k++;
if(k>=3)
{
for(int j=i;j>=i-k+1;j--)
{
sum[j]-=2;
}
dfs(v+1);
for(int j=i;j>=i-k+1;j--)
{
sum[j]+=2;
}
}
}
}
k=0;
for(int i=3;i<=14;i++)
{
if(sum[i]<=2)k=0;
else
{
k++;
if(k>=2)
{
for(int j=i;j>=i-k+1;j--)
{
sum[j]-=3;
}
dfs(v+1);
for(int j=i;j>=i-k+1;j--)
{
sum[j]+=3;
}
}
}
}
for(int i=2;i<=14;i++)
{
if(sum[i]<=3)
{
if(sum[i]<=2)continue;
sum[i]-=3;
for(int j=2;j<=15;j++)
{
if(!(sum[j]<=0 || i==j))
{
sum[j]--;
dfs(v+1);
sum[j]++;
}
}
for(int j=2;j<=14;j++)
{
if(!(sum[j]<=0 || i==j))
{
sum[j]-=2;
dfs(v+1);
sum[j]+=2;
}
}
sum[i]+=3;
}
else
{
sum[i]-=3;
for(int j=2;j<=15;j++)
{
if(!(sum[j]<=0 || i==j))
{
sum[j]--;
dfs(v+1);
sum[j]++;
}
}
for(int j=2;j<=14;j++)
{
if(!(sum[j]<=1 || i==j))
{
sum[j]-=2;
dfs(v+1);
sum[j]+=2;
}
}
sum[i]+=3;
sum[i]-=4;
for(int j=2;j<=15;j++)
{
if(!(sum[j]<=0 || i==j))
{
sum[j]--;
for(int k=1;k<=14;k++)
{
if(!(sum[k]<=0 || j==k))
{
sum[k]--;
dfs(v+1);
sum[k]++;
}
}
sum[j]++;
}
}
for(int j=2;j<=14;j++)
{
if(!(sum[j]<=1 || i==j))
{
sum[j]-=2;
for(int k=1;k<=13;k++)
{
if(!(sum[k]<=1 || j==k))
{
sum[k]-=2;
dfs(v+1);
sum[k]+=2;
}
}
sum[j]+=2;
}
}
sum[i]+=4;
}
}
for(int i=2;i<=15;i++)
{
if(sum[i])
{
v++;
}
}
ans=min(ans,v);
}
int main()
{
cin>>t>>n;
for(int i=1;i<=t;i++)
{
ans=0x7fffffff;
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
if(x==0)
{
sum[15]++;
}
else if(x==1)
{
sum[14]++;
}
else
{
sum[x]++;
}
}
dfs(0);
ans2[i]=ans;
}
for(int i=1;i<=t;i++)
{
cout<<ans2[i]<<endl;
}
return 0;
}
复制代码
欢迎光临 华师一附中OI组 (http://hsyit.cn/)
Powered by Discuz! X3.2