WEEK6 模拟题
题目大意
给出两个数A,B,表示牌的大小为:0到A-1, 花色为:0到B-1,再给出a1,b1,a2,b2,表示:(a1,b1),(a2,b2)两张牌,现从其余牌中再拿出3张牌,现要求预测以下9种情况,对应的5张牌的组合个数,按照低序号优先原则记数。
同花顺: 同时满足规则 2 和规则 3.
顺子 : 5张牌的大小形如 x, x + 1, x + 2, x + 3, x + 4
同花 : 5张牌都是相同花色的.
炸弹 : 5张牌其中有4张牌的大小相等.
三带二 : 5张牌其中有3张牌的大小相等,且另外2张牌的大小也相等.
两对: 5张牌其中有2张牌的大小相等,且另外3张牌中2张牌的大小相等.
三条: 5张牌其中有3张牌的大小相等.
一对: 5张牌其中有2张牌的大小相等.
要不起: 这手牌不满足上述的牌型中任意一个.
思路
这个题最好的思路就是直接枚举所有的组合情况,由于数据量很小,最坏情况就是 O ( 25 ∗ 25 ∗ 25 ∗ 4 ∗ 4 ∗ 4 ) O(25*25*25*4*4*4) O(25∗25∗25∗4∗4∗4),也就是1e6的复杂度,所以直接DFS枚举就可以,只需要注意3点:
- 同一组内不能有牌的花色和大小完全相同的牌
- 低序号优先,同花顺不能再属于顺子或同花。
- 最后要除掉顺序,也就是所有结果除 A 3 3 = 6 A^3_3=6 A33=6
代码
#include<bits/stdc++.h>
using namespace std;
int ans[10];
int num[10];
int color[10];
int cnt=0;
int a=0,b=0;
int a1=0,a2=0,b1=0,b2=0;
bool flag=0;
void check()
{
bool isseq=0; //
bool samech=0;
int num2[10];
int col2[10];
for(int k=1;k<=5;k++){
num2[k]=num[k];
col2[k]=color[k];
}
sort(num2+1,num2+6);
for(int i=1;i<5;i++){
if(num2[i]+1!=num2[i+1]){
isseq=0;
break;
}
else isseq=1;
}
sort(col2+1,col2+6);
if(col2[1]==col2[5]) samech=1;
if(isseq ==1 && samech==1) ans[0]++;
else if(isseq==1) ans[1]++;
else if(samech==1) {
ans[2]++; // if is samechar , can't be else
// for(int j=1;j<=5;j++) cout<<num2[j]<<" : "<<col2[j]<<endl;
// cout<<endl;
}
//bomb
else if(num2[1]==num2[4]&&num2[4]!=num2[5]) ans[3]++;
else if(num2[1]!=num2[2]&&num2[2]==num2[5]) ans[3]++;
//3 +2
else if(num2[1]==num2[3]&&num2[4]==num2[5]) ans[4]++;
else if(num2[1]==num2[2]&&num2[3]==num2[5]) ans[4]++;
// 2 pair
else if(num2[1]==num2[2] && num2[3] == num2[4]) ans[5]++;
else if(num2[1]==num2[2] && num2[4]==num2[5]) ans[5]++;
else if(num2[2]==num2[3]&&num2[4]==num2[5]) ans[5]++;
//3tiao
else if(num2[1]==num2[3]||num2[2]==num2[4]||num2[3]==num2[5]) ans[6]++;
//1 pair
else if(num2[1]==num2[2] || num2[2]==num2[3] || num2[3]==num2[4] ||num2[4]==num2[5])
ans[7]++;
//nothing
else ans[8]++;
}
void solve(int i)
{
if(i==6)
{
check(); //计算
return;
}
else if(i<=5)
{
for(int j=0;j<a;j++)
{
for(int k=0;k<b;k++)
{
num[i]=j;
color[i]=k;
for(int s =1;s<i;s++)
{ //判断刚加入的牌,是否和前边重复
if(num[i]==num[s] && color[i]==color[s])
{
flag=1;
break;
}
}
if(flag==0) solve(i+1);
else flag=0;
}
}
}
}
int main()
{
scanf("%d%d",&a,&b);
scanf("%d%d%d%d",&a1,&b1,&a2,&b2);
memset(num,0,sizeof num);
memset(color,0,sizeof color);
memset(ans,0,sizeof ans);
num[1]=a1,num[2]=a2;
color[1]=b1,color[2]=b2;
solve(3);
for(int i=0;i<9;i++)
{
if(i==0) printf("%d",ans[0]/6); //除顺序
else printf(" %d",ans[i]/6);
}
cout<<endl;
return 0;
}
注意点
这种模拟题不是数学题,这个题数据量很小,明显直接DFS就可以解决,不需要根据排列组合算答案,那就不是模拟题了。这里附一下大半天排列组合的计算结果(这也是为什么考试的时候没做完的原因,一定要注意这一点,思路要找准.)
#include<bits/stdc++.h>
using namespace std;
int ans[10];
int temp[10];
int a=0,b=0;
int a1=0,a2=0,b1=0,b2=0;
//memset(ans,0,sizeof ans);
int kind=0;
int samech=0;
bool isseq() //顺子
{
if(abs(a1-a2)<5&&a1!=a2)
{
for(int i=0;i<a;i++)
for(int j=0;j<a;j++)
for(int k=0;k<a;k++)
{
temp[0]=a1;
temp[1]=a2;
temp[2]=i,temp[3]=j,temp[4]=k;
if(a1!=a2&&a2!=i&&i!=j&&j!=k)
{
sort(temp,temp+5);
if(temp[0]+1==temp[1]&&temp[1]+1==temp[2]&&
temp[2]+1==temp[3]&&temp[3]+1==temp[4]) kind++;
}
}
kind/=6;
}
if(kind>0) return 1;
else return 0;
}
bool samechar()
{
if(b1==b2)
{
samech=(a-2)*(a-3)*(a-4)/6; //同花
return 1;
}
return 0;
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%d",&a,&b);
scanf("%d%d%d%d",&a1,&b1,&a2,&b2);
if(isseq()&&samechar())
{
ans[0]=kind; //同花顺
}
if(isseq()) ans[1]=kind*(b*b*b)-ans[0];
if(samechar()) ans[2]=samech-ans[0];
if(b==4)
{ //炸弹
if(a1!=a2) ans[3]=2;
else if(a1==a2) ans[3]=(a-1)*b;
}
if(b>=3) //3带2
{
if(a1!=a2) ans[4]=(b-1)*(b-2)*(b-1);
else if(a1==a2) ans[4]=(b-2)*(a-1)*(b-1)*b/2+(b)*(b-1)*(b-2)*(a-1)/6;
}
if(b>=2) //两对
{
if(a1!=a2) ans[5]=2*b*(b-1)*(b-1)*(a-2);
else if(a1==a2) ans[5]=(a-1)*b*(b-1)*(a-2)*b/2;
}
if(b>=3) //三条
{
if(a1==a2) ans[6]=b*b*(b-2)*(a-1)*(a-2)/2;
else if(a1!=a2) {
ans[6]=b*(b-1)*(b-2)*(a-2)+(a-2)*b*(b-1)*(b-2)/6;
// cout<<b*(b-1)*(b-2)*(a-2)<<" "<<(a-2)*b*(b-1)*(b-2)/6<<endl;
}
}
if(b>=2) //一对
{
if(a1==a2) ans[7]=(a-1)*(a-2)*(a-3)/6*b*b*b;
else if(a1!=a2) ans[7]=(b-1)*b*b*(a-2)*(a-3)/2+(b-1)*b*b*(a-2)*(a-3);
}
if(a1!=a2)
{
if(b1!=b2) ans[8]=b*b*b*(a-2)*(a-3)*(a-4)/6-ans[1]; //去顺子
else if(b1==b2) { ans[8]=(b*b*b-1)*(a-2)*(a-3)*(a-4)/6-ans[1];
//不是同花色的不一样的序列 减顺子+同花顺
}
}
for(int i=0;i<9;i++)
{
if(i==0) printf("%d",ans[0]);
else printf(" %d",ans[i]);
}
cout<<endl;
return 0;
}
月模拟题:ASCII码画图
题目大意:
定义两种操作:
- 画线:0 x1,y1,x2, y2 ;给出两个端点的坐标,画一条连接这两个端点的线段。简便起见题目保证要画的每条线段都是水平或者竖直的。水平线段用字符 - 来画,竖直线段用字符 | 来画。如果一条水平线段和一条竖直线段在某个位置相交,则相交位置用字符 + 代替。
- 填充:1,x1,y1,x2,y2 ,C ; 给出填充的起始位置坐标和需要填充的字符,从起始位置开始,用该字符填充相邻位置,直到遇到画布边缘或已经画好的线段。注意这里的相邻位置只需要考虑上下左右 4 个方向。填充的字符为大写字母
所有的点初始都是‘.’,根据给出的命令,画出对应的ASCII形成的图。
输入:
16 13 9
0 3 1 12 1
0 12 1 12 3
0 12 3 6 3
0 6 3 6 9
0 6 9 12 9
0 12 9 12 11
0 12 11 3 11
0 3 11 3 1
1 4 2 C
效果:
................
...+--------+...
...|CCCCCCCC|...
...|CC+-----+...
...|CC|.........
...|CC|.........
...|CC|.........
...|CC|.........
...|CC|.........
...|CC+-----+...
...|CCCCCCCC|...
...+--------+...
................
思路
这个题只需在初始化好画布之后,根据要求画线或填充相应的字母即可,只需注意:
- 画线操作交叉点是’+’,特别注意的是,无论’-‘或’|’,若下一个填充位置是‘+’,则应该跳过,保持’+'不变。
- 填充的时候,是一个BFS的操作,以画布,’-’, ‘+’, ‘|’ 为界限,其余位置只要不等于当前待填充字符,都可以填充。
代码
由于题目中的坐标和二位数组中的坐标是不一样的,(二者相当于关于题目坐标系的X轴对称),所以需要注意:
- BFS的时候,实际填入二维数组中的时候,题目的横纵坐标要互换。(原坐标系的(3,2), 相当于二维数组的第3列,第2行)
- 输出的时候,需要从最后一行开始输出,直到输出第0行,但是列的顺序不需要改变。
#include<bits/stdc++.h>
using namespace std;
int m=0,n=0,q=0;
char a[200][200];
int x=0,y=0;
char c='0';
int x1=0,x2=0,y1=0,y2=0;
struct point{
int x,y;
point(int _x,int _y){
x=_x;
y=_y;
}
};
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
queue<point> qu;
void bfs()
{
qu.push(point(x,y));
while(!qu.empty())
{
point p=qu.front();
qu.pop();
for(int k =0;k<4;k++)
{
int nx=p.x;
int ny=p.y;
nx+=dx[k];
ny+=dy[k];
if(nx>=0&&nx<m&&ny>=0&&ny<n&&a[ny][nx]!='|'&&a[ny][nx]!='-'&&a[ny][nx]!=c&&a[ny][nx]!='+')
{
a[ny][nx]=c;
qu.push(point(nx,ny));
}
}
}
}
int main()
{
// freopen("15in.txt","r",stdin);
scanf("%d%d%d",&m,&n,&q);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)
a[i][j]='.';
}
int cmd=0;
for(int i=0;i<q;i++)
{
scanf("%d",&cmd);
if(cmd==0)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(x1==x2){
int j=max(y1,y2);
int k=min(y1,y2);
for(;k<=j;k++)
{
if(a[k][x1]!='-'&&a[k][x1]!='+') a[k][x1]='|';
else a[k][x1]='+';
}
}
else if(y1==y2){
int k=max(x1,x2);
int j=min(x1,x2);
for(;j<=k;j++)
{
if(a[y1][j]!='|'&&a[y1][j]!='+')a[y1][j]='-'; //attention, original is plus,not replace
else a[y1][j]='+';
}
}
// for(int i=n-1;i>=0;i--)
// {
// for(int k=0;k<m;k++)
// {
// printf("%c",a[i][k]);
// }
// printf("\n");
// }
}
else if(cmd==1){
char tmp;
scanf("%d%d%c%c",&x,&y,&tmp,&c);
bfs();
// for(int i=n-1;i>=0;i--)
// {
// for(int k=0;k<m;k++)
// {
// printf("%c",a[i][k]);
// }
// printf("\n");
// }
//
}
}
for(int i=n-1;i>=0;i--)
{
for(int k=0;k<m;k++)
{
printf("%c",a[i][k]);
}
printf("\n");
}
return 0;
}