[ZJOI2006]超级麻将(可行性dp)
题目描述
要判断某人是否胡牌,显然一个弱智的算法就行了,某中学信息学小组超级麻将迷想了想,决定将普通麻将改造成超级麻将。
所谓超级麻将没有了砣、索、万的区分,每种牌上的数字可以是1~100,而每种数字的牌各有100张。另外特别自由的是,玩牌的人手里想拿多少张牌都可以,好刺激哦!
刺激归刺激,但是拿多了怎么胡牌呢?
超级麻将规定只要一个人手里拿的牌是若干句话(三个连续数字的牌各一张组成一句话,三张或者四张同样数字的牌也算一句话),再加上一对相同的牌,就算胡了。
作为信息学竞赛选手的你,麻烦你给这位超级麻将迷编个程序,判断能否胡牌。
Solution
可行性dp,设dp[i][j][k][0/1]为到第i个,当前用了k个,上一次用j个,出没出对子,能否可行。
转移:
出顺,则必须保证dp[i-1][a[i-2]-k][j-k][0/1]。
然后讨论一下出对,三个的,四个的,同层转移,
Code
#include<iostream> #include<cstdio> #include<bitset> #include<cstring> using namespace std; bool dp[101][101][101][2]; int t,b[10],a[102]; int rd(){ int x=0;char c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c)){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); } return x; } int main(){ t=rd(); while(t--){ memset(dp,0,sizeof(dp));dp[0][0][0][0]=1; for(int i=1;i<=100;++i){ a[i]=rd(); for(int j=0;j<=a[i-1];++j) for(int k=0;k<=a[i];++k){ if(k>1)dp[i][j][k][1]|=dp[i][j][k-2][0]; if(k>2)dp[i][j][k][1]|=dp[i][j][k-3][1],dp[i][j][k][0]|=dp[i][j][k-3][0]; if(k>3)dp[i][j][k][1]|=dp[i][j][k-4][1],dp[i][j][k][0]|=dp[i][j][k-4][0]; if(j>=k&&a[i-2]>=k)dp[i][j][k][0]|=dp[i-1][a[i-2]-k][j-k][0],dp[i][j][k][1]|=dp[i-1][a[i-2]-k][j-k][1]; } } printf(dp[100][a[99]][a[100]][1]?"Yes\n":"No\n"); } return 0; }