problem
Description
Input
Output
Sample Input
输入1:
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
输入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
Sample Output
输出1:
3
输出2:
6
Data Constraint
analysis
暴♂力的技♂巧
NOIP的大搜索毒瘤题……
而且大小王加起来看做对子……牌型里没有飞机和飞机带翅膀……
真当我不会玩斗地主么……(滑稽.jpg)
自然而然地想到dfs来解决这道题目(花色一点用都没有)
如果我们把顺子三带一二四带二火箭炸弹和单张对子打全放在一起dfs,TLE30分
于是我们需要一点暴力的技♂巧(FLAG)
顺子
由于顺子是唯一对点数有要求的牌型,于是我们可以先暴力搜索单、双、三顺的情况
(注意顺子从长到短dfs,因为大部分情况长的比短的优)
炸弹、三张、四带二和三带一二
当顺子全部打出后,再dfs 炸弹、三张
注意这里的技巧,就是你完全不用去中途dfs四带二、三带一二,因为那会有非常非常的的额外状态
多的状态代表多的时间,其实TLE30的时间基本都浪费在dfs四带二、三带一二上面了
我们可以把出的炸弹、三张有多少个记录下来,到了剩下散牌时尽量把单张和对子塞进炸弹和三张里
当然,先dfs炸弹再dfs三张,明显炸弹比三张能带跑更多牌,也优得多
单张和对子
最后剩下的只有单张和对子了
把尽可能多的单张、对子塞进炸弹、三张里
剩下塞不进的单张、对子单独打出即可
code
真的看起来都烦更别说打代码……
#include<stdio.h>
#include<string.h>
#define MAXN 15
using namespace std;
int a[MAXN];
int t,n,ans;
int min(int x,int y)
{
return x<y?x:y;
}
int read()
{
int x=0,f=1;
char ch=getchar();
while (ch<'0' || '9'<ch)
{
if (ch=='-')f=-1;
ch=getchar();
}
while ('0'<=ch && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
__attribute__((optimize("-O3")))
void dfs(int m,int tot,int three,int four)
{
bool flag=1;
if (m>ans)return;
if (tot==0)
{
ans=min(ans,m);
return;
}
if (tot>=5)
for (int i=1;i<=8;i++)
{
for (int j=12;j-i+1>=5;j--)
{
bool bz=1;
for (int k=i;k<=j;k++)
if (a[k]<1)
{
bz=0;
break;
}
if (bz)
{
flag=0;
for (int k=i;k<=j;k++)a[k]--;
dfs(m+1,tot-(j-i+1),three,four);
for (int k=i;k<=j;k++)a[k]++;
}
}
}
if (tot>=6)
for (int i=1;i<=10;i++)
{
for (int j=12;j-i+1>=3;j--)
{
bool bz=1;
for (int k=i;k<=j;k++)
if (a[k]<2)
{
bz=0;
break;
}
if (bz)
{
flag=0;
for (int k=i;k<=j;k++)a[k]-=2;
dfs(m+1,tot-2*(j-i+1),three,four);
for (int k=i;k<=j;k++)a[k]+=2;
}
}
}
if (tot>=6)
for (int i=1;i<=11;i++)
{
for (int j=12;j-i+1>=2;j--)
{
bool bz=1;
for (int k=i;k<=j;k++)
if (a[k]<3)
{
bz=0;
break;
}
if (bz)
{
flag=0;
for (int k=i;k<=j;k++)a[k]-=3;
dfs(m+1,tot-3*(j-i+1),three,four);
for (int k=i;k<=j;k++)a[k]+=3;
}
}
}
if (tot>=3)
for (int i=1;i<=13;i++)
if (a[i]>=3)
{
flag=0;
a[i]-=3;
dfs(m+1,tot-3,three+1,four);
a[i]+=3;
if (a[i]==4)
{
a[i]=0;
dfs(m+1,tot-4,three,four+1);
a[i]=4;
}
}
if (flag)
{
int one=0,two=0;
int i=1;
for (i=1;i<=14;i++)
{
if (a[i]==1)one++;
else if (a[i]==2)two++;
}
if (four*2<=one)
{
one-=four*2;
four=0;
}
else
{
four-=one/2;
one-=(one/2)*2;
}
if (four*2<=two)
{
two-=four*2;
four=0;
}
else
{
four-=two/2;
two-=(two/2)*2;
}
if (four && one)one--;
if (three<=one)
{
one-=three;
three=0;
}
else
{
three-=one;
one=0;
}
if (three<=two)
{
two-=three;
three=0;
}
else
{
three-=two;
two=0;
}
if (m+one+two<ans)ans=m+one+two;
}
}
int main()
{
freopen("landlords.in","r",stdin);
freopen("landlords.out","w",stdout);
//freopen("read.txt","r",stdin);
//freopen("write.txt","w",stdout);
t=read(),n=read();
while (t--)
{
ans=n;
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++)
{
int x=read(),y=read();
if (x==1)a[12]++;
else if (x==2)a[13]++;
else if (x==0)a[14]++;
else a[x-2]++;
}
dfs(0,n,0,0);
printf("%d\n",ans);
}
return 0;
}
LOL
啊我以后再也不做毒瘤题了