机考 出牌顺序 dfs
题目:
给定一堆牌,每张牌都有数字和颜色,选手从中选出一张后,只能再挑选颜色或者数字和上一张相同的牌,否则不能抽选
选手应该怎么选才能使得抽选的次数最大,并且输入这个最大次数
输入
第一行 牌的数值n (1<=n<=10)
第二行 牌的颜色(r,l,g,t四种颜色表示)
输入
抽取的最大次数
示例:
输入
4 1 3 5 4
r g t r n
输出
3
这个题当时尝试了50分钟没搞出来,因为之前没做过广度优先法的题,没这个思维。后来看了下网友的思路
参考LeetCode547,本质就是BFS进行图的遍历,找到最大连通的子图的节点数
随手写了一下代码,没有进一步进行优化,但是应该是OK的。
-
def findMaxCards(cards):
-
'''
-
广度优先搜索-队列
-
图的遍历,一个节点出对,相连通的节点入对,当队列为空,则表示已经遍历完了一个连通的子图
-
输入:卡片的列表,内容为数字 颜色,如['4r','5r','4n','3t','1g']
-
输出:最大连通子图的卡牌数量
-
'''
-
# 先将输入列表转化成邻接矩阵,若两个节点数字相同或颜色相同,则连通
-
n = len(cards)
-
matrix = [[0 for _ in range(n)] for _ in range(n)]
-
for i in range(n):
-
for j in range(n):
-
if cards[i][0]==cards[j][0] or cards[i][1]==cards[j][1]:
-
matrix[i][j]=1
-
# BFS进行广度搜索,队列实现
-
visited = [0 for _ in range(n)] # 记录访问过的卡片
-
max_res = 0 # 记录最大的连通子图的节点个数
-
-
temp = 0 # 记录每个连通子图的节点个数
-
for card_idx in range(n):
-
if visited[card_idx]==0:
-
queue = [card_idx]
-
visited[card_idx]=1
-
else:
-
continue
-
-
while queue:
-
i = queue.pop(0)
-
temp =1
-
for j in range(n):
-
if matrix[i][j]==1 and visited[j]==0 and i!=j:
-
queue.append(j)
-
visited[j]=1
-
max_res = max(max_res,temp)
-
temp = 0
-
return max_res
-
-
cards = ['4r','5r','4n','3t','1g']
-
print(findMaxCards(cards))
我没看懂,但是我感觉算的并不对
我按照这个思路,给了一个例子:
1 2 3 3 5 5
a b b c b a
序号 |
0 |
1 |
2 |
3 |
4 |
5 |
数字 |
1 |
2 |
3 |
3 |
5 |
5 |
花色 |
a |
b |
b |
c |
b |
a |
我需要先把这些牌之间的关系找出来,就是按数字比相等或者按照花色比相同
record |
0 |
1 |
2 |
3 |
4 |
5 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
0 |
2 |
0 |
1 |
1 |
1 |
1 |
0 |
3 |
0 |
0 |
1 |
1 |
0 |
0 |
4 |
0 |
1 |
1 |
0 |
1 |
1 |
5 |
1 |
0 |
0 |
0 |
1 |
1 |
然后再记录一个map,每次出一张牌,都要将这个牌的map位置1,这样下次就不再找这个牌了
map |
0 |
1 |
2 |
3 |
4 |
5 |
0 |
0 |
0 |
0 |
0 |
0 |
思路就是,假设从每一个牌开始出,计算后面在这个牌为前的所有可能性,然后可以接的牌,再作为前一个牌,去找接下来的其他牌的可能性.......依次查下去,这肯定需要递归的思想。
麻烦的在于,牌出了一次就不能再出了,但是我先按照一个排序查找后,置map,又不能影响后面可能性的map,这就需要每次从一个情况往下找时,用自身独立的map,不影响其他情况。
每次找到一张牌的可能性后,都要计数 1再加上下一次查找的值,返回。
比如说,我先出第一张牌,置map[0]=1;再找下一张牌的可能性, 根据record[0][i] (i!=0)发现只有i=5的可能性; count
然后5再找下一张,置map[5]=1;根据record[0][i] (i!=0)发现只有i=4的可能性; count
然后4再找下一张,置map[4]=1;根据record[0][i] (i!=0)发现有i=1;i=2的可能性;(i=4不能等于自己,和i=5已经用过了,所以排除) count
然后1再找下一张,同时2再找下一张。。。(这就需要同时查两种情况了,算出来的可能性,取最大值返回)
.........
这样到最后,map也满了,或者找不到record == 1的情况了,就返回0,就结束了这个路径的递归查找了。
-
-
-
-
-
-
char record[10][10] = {0}; // 记录牌和牌之间的关系
-
int card_num = 0;
-
// pOutNum是这次找到的lastNum接这个牌的最优解
-
int findMatch(char *pMap, int lastNum, int targetNum){
-
char map_temp[10] = {0};
-
int num[10] = {0};
-
int max_num = 0;
-
-
memcpy(map_temp, pMap, 10);
-
for(int i=0; i<card_num; i ){
-
if(map_temp[i] == 0 && record[lastNum][i] && lastNum != i){
-
map_temp[i] = 1;
-
num[i] = 1 findMatch(map_temp, i, targetNum-1);
-
max_num = get_max(max_num, num[i]);
-
if(targetNum == max_num){
-
printf("%d ", i);
-
break;
-
}
-
}
-
}
-
return max_num;
-
}
-
int main(){
-
// char card[10][2] = {{'1', 'a'}, {'2', 'b'}, {'3', 'a'}, {'3', 'c'}, {'5', 'b'}, {'5', 'a'}};
-
char card[10][2] = {0};
-
char map[10] = {0}; // 记录路径是否用过某个牌
-
int max_num = 0;
-
int num[10] = {0}; // 从i开始的牌的最大值
-
-
memset(record, 0, sizeof(record));
-
while(scanf("%[0-9]", &card[card_num][0]) != 0){
-
card_num ;
-
if(getchar() == '\n'){
-
break;
-
}
-
}
-
printf("card_num:%d\n", card_num);
-
for(int i=0; i<card_num; i ){
-
scanf("%c ", &card[i][1]);
-
}
-
for(int i=0; i<card_num; i ){
-
printf("card[%d]: %c %c ", i, card[i][0], card[i][1]);
-
}
-
printf("\n");
-
-
for(int i=0; i<card_num; i ){
-
for(int k=0; k<card_num; k ){
-
if(card[i][0] == card[k][0] || card[i][1] == card[k][1]){
-
record[i][k] = 1;
-
}
-
printf("%d ", record[i][k]);
-
}
-
printf("\n");
-
}
-
for(int i=0; i<card_num; i ){
-
char map_temp[10] = {0};
-
memcpy(map_temp, map, 10);
-
map_temp[i] = 1;
-
printf("\nnum:%d ", i);
-
num[i] = findMatch(map_temp, i, card_num);
-
max_num = get_max(max_num, num[i]);
-
}
-
-
for(int i=0; i<card_num; i ){
-
if(max_num == num[i]){
-
char map_temp[10] = {0};
-
memcpy(map_temp, map, 10);
-
map_temp[i] = 1;
-
printf("\nnum---:%d ", i);
-
findMatch(map_temp, i, num[i]);
-
}
-
}
-
printf("\nmax:%d\n", max_num 1); // 上面查到的是以某一张牌开始的后面找到的牌数,还应加上自身
-
}
上面代码的targetNum其实就是为了找出路径,不然就只要找到返回值的最大值就可以了。
找出经历过的路径也比较麻烦,因为递归的时候并不知道哪个才是最大的可能性,得都找到最大值后,再找到第一张开始的,再来一遍
输入:
1 2 3 3 5 5
a b b c b a
输出:
card_num:6
card[0]: 1 a card[1]: 2 b card[2]: 3 b card[3]: 3 c card[4]: 5 b card[5]: 5 a
1 0 0 0 0 1
0 1 1 0 1 0
0 1 1 1 1 0
0 0 1 1 0 0
0 1 1 0 1 1
1 0 0 0 1 1
num:0
num:1
num:2
num:3
num:4
num:5
num---:0 3 2 1 4 5
num---:3 0 5 4 1 2
max:6
可以看到从牌0和牌3开始,路径都最长
序号 |
0 |
1 |
2 |
3 |
4 |
5 |
数字 |
1 |
2 |
3 |
3 |
5 |
5 |
花色 |
a |
b |
b |
c |
b |
a |
0 5 4 1 2 3
3 2 1 4 5 0
我一直对算法类的东西感觉很困难,递归啊之类的,还是得多练
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfaeccb
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01