DFS的複雜題意大模擬(CSP-T3方向)
題目概述
題目敘述
從瑞神家打牌回來後,東東痛定思痛,決定苦練牌技,終成賭神!
東東有 A × B 張撲克牌。每張撲克牌有一個大小(整數,記爲a,範圍區間是 0 到 A - 1)和一個花色(整數,記爲b,範圍區間是 0 到 B - 1。
撲克牌是互異的,也就是獨一無二的,也就是說沒有兩張牌大小和花色都相同。
“一手牌”的意思是你手裏有5張不同的牌,這 5 張牌沒有誰在前誰在後的順序之分,它們可以形成一個牌型。 我們定義了 9 種牌型,如下是 9 種牌型的規則,我們用“低序號優先”來匹配牌型,即這“一手牌”從上到下滿足的第一個牌型規則就是它的“牌型編號”(一個整數,屬於1到9):
1同花順: 同時滿足規則 5 和規則 4.
2炸彈 : 5張牌其中有4張牌的大小相等.
3三帶二 : 5張牌其中有3張牌的大小相等,且另外2張牌的大小也相等.
4同花 : 5張牌都是相同花色的.
5順子 : 5張牌的大小形如 x, x + 1, x + 2, x + 3, x + 4
6三條: 5張牌其中有3張牌的大小相等.
7兩對: 5張牌其中有2張牌的大小相等,且另外3張牌中2張牌的大小相等.
8一對: 5張牌其中有2張牌的大小相等.
9要不起: 這手牌不滿足上述的牌型中任意一個.
現在, 東東從A × B 張撲克牌中拿走了 2 張牌!分別是 (a1, b1) 和 (a2, b2). (其中a表示大小,b表示花色)
現在要從剩下的撲克牌中再隨機拿出 3 張!組成一手牌!!
其實東東除了會打代碼,他業餘還是一個魔法師,現在他要預言他的未來的可能性,即他將拿到的“一手牌”的可能性,我們用一個“牌型編號(一個整數,屬於1到9)”來表示這手牌的牌型,那麼他的未來有 9 種可能,但每種可能的方案數不一樣。
現在,東東的阿戈摩托之眼沒了,你需要幫他算一算 9 種牌型中,每種牌型的方案數。
INPUT
第 1 行包含了整數 A 和 B (5 ≤ A ≤ 25, 1 ≤ B ≤ 4).
第 2 行包含了整數 a1, b1, a2, b2 (0 ≤ a1, a2 ≤ A - 1, 0 ≤ b1, b2 ≤ B - 1, (a1, b1) ≠ (a2, b2)).
OUTPUT
輸出一行,這行有 9 個整數,每個整數代表了 9 種牌型的方案數(按牌型編號從小到大的順序)
輸入輸出樣例
第一組:
輸入樣例:
5 2
1 0 3 1
輸出樣例:
0 0 0 0 8 0 12 36 0
第二組:
輸入樣例:
25 4
0 0 24 3
輸出樣例:
0 2 18 0 0 644 1656 36432 113344
題目重述
題目一眼就能看出時一道典型的大模擬題:複雜的設定、繁多的場景要求、大量的分支種類,靜下心來分析題目的考察方向和核心算法。
通過劃去無用的場景,可以將問題縮減爲:
給定牌的數值大小和花色數量,範圍內的牌面都可以選用。現給定2張牌面,選擇剩下的三張牌並且形成一套牌面(每張牌不可重複選擇)
對得到的牌面,分成9個類別。要求計算所有得到的牌面,並統計9種牌面出現的次數
解題思路
通過對題意的剖析,可以看出整個任務分成兩個部分:
1、得到所有牌面可能取值
2、根據牌面進行分類並統計個數
任務1解決方案:
注意到題目中是要求遍歷全部的牌面,說到遍歷那就可以清晰地將算法確定到DFS或者BFS上面。,由於在遍歷過程中要求遍歷所有情況且需要判斷牌面所屬類型,方便數據的存儲,選用DFS可以使編碼更爲簡單有效。
(如果選用BFS,要存儲前置節點等問題,增大工作量和錯誤概率)
任務二解決方案:
分析9種牌面我們可以得到下面的分析:
對花色的分類只有兩類:同花 & 非同花
對數值的分類有兩個維度:
1、五張牌是否是順子
2、如果不是順子,有多少張重複的牌型
分析清楚只需要簡單的操作就可以完成分類:
一重判斷–是否同花:遍歷訪問五張牌的花色即可完成
二重判斷–是否順子:使用STL中的sort()函數排序,再判斷五個數值的大小是否階梯性+1增長即可
三重判斷–如果不是順子,初始化一個計數數組統計每個數值的出現次數,分情況寫分支即可解決。
總結
大模擬題,看似題目難懂,十分複雜困難,容易給人帶來畏懼心理。但若能夠沉下心,仔細分析題意,將核心算法與其他任務剝離開,分成模塊解決,一切迎刃而解。
題目源碼
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int num=0;//要處理的數字個數
int col=0;//要處理的花色個數
struct card
{
int number;
int color;
bool operator<(card & a)
{
return number<a.number;
}
}cards[5];
int vis [26][5];
int cont=0;
int list[9];
int number_list[26];
void critize(card cin_card[5])
{
cont++;
int col_flag=1;
int num_flag=0;
int flag_3=0;
int flag_2=0;
int col_1=cin_card[0].color;
card card_copy[5];
for(int i=0;i<5;i++)
{
card_copy[i].number=cin_card[i].number;
card_copy[i].color=cin_card[i].color;
}
sort(card_copy,card_copy+5);
/*for(int i=0;i<5;i++)
{
cout<<card_copy[i].number<<" "<<card_copy[i].color<<endl;
}*/
if(card_copy[0].number==card_copy[1].number-1 && card_copy[1].number==card_copy[2].number-1 && card_copy[2].number==card_copy[3].number-1 && card_copy[3].number==card_copy[4].number-1)
num_flag=5;
for(int i=0;i<num;i++)
{
number_list[i]=0;
}
for(int i=0;i<5;i++)
{
if(card_copy[i].color!=col_1)
{
col_flag=0;
}
number_list[card_copy[i].number]++;
}
for(int i=0;i<num;i++)
{
if(number_list[i]==2)
{
flag_2++;
}
else if(number_list[i]==3)
{
flag_3++;
}
else if(number_list[i]==4)
{
num_flag=4;
break;
}
}
if(num_flag==5 && col_flag==1)
{
list[0]++;
return;
}
if(num_flag==4)
{
list[1]++;
return;
}
if(flag_2==1 && flag_3==1)
{
list[2]++;
return;
}
if(col_flag==1)
{
list[3]++;
return;
}
if(num_flag==5)
{
list[4]++;
return;
}
if(flag_3==1)
{
list[5]++;
return;
}
if(flag_2==2)
{
list[6]++;
return;
}
if(flag_2==1)
{
list[7]++;
return;
}
list[8]++;
}
void DFS(int step)
{
for(int i=0;i<num;i++)
for(int j=0;j<col;j++)
{
int dx=i;
int dy=j;
if(vis[dx][dy]==0)
{
step++;
cards[step].number=dx;
cards[step].color=dy;
vis[dx][dy]=1;
if(step==4)
{
critize(cards);
}
else
{
DFS(step);
}
step--;
vis[dx][dy]=0;
}
}
}
int main()
{
cin>>num>>col;
int a1,b1,a2,b2=0;
cin>>a1>>b1;
cin>>a2>>b2;
cards[0].number=a1;
cards[0].color=b1;
cards[1].number=a2;
cards[1].color=b2;
for(int i=0;i<num;i++)
for(int j=0;j<col;j++)
vis[i][j]=0;
vis[a1][b1]=1;
vis[a2][b2]=1;
/*for(int i=0;i<num;i++)
{
for(int j=0;j<col;j++)
{
cout<<vis[i][j]<" ";
}
cout<<endl;
}*/
for(int i=0;i<9;i++)
list[i]=0;
DFS(1);
for(int i=0;i<9;i++)
{
cout<<list[i]/6<<endl;
}
return 0;
}