巧妙用栈的思想解题

巧妙用栈的思想解题

标签:C语言 栈 数组

by 小威威


这里我们就通过实例来了解如何运用栈的思想(不是用栈解题噢,是用栈的思想)

实例:

N couples are standing in a circle, numbered consecutively clockwise from 1 to 2N. Husband and wife do not always stand together. We remove the couples who stand together until the circle is empty or we can’t remove a couple any more.

Can we remove all the couples out of the circle?

Input
There may be several test cases in the input file. In each case, the first line is an integer N(1 <= N <= 100)—-the number of couples. In the following N lines, each line contains two integers —- the numbers of each couple.
N = 0 indicates the end of the input.

Output
Output “Yes” if we can remove all the couples out of the circle. Otherwise, output “No”.

Sample Input
4
1 4
2 3
5 6
7 8

2
1 3
2 4

6
1 12
2 11
3 10
4 9
5 6
7 8

7
1 14
4 13
2 3
5 10
12 11
6 9
7 8

0
Sample Output
Yes
No
Yes
Yes

# include <stdio.h>
int main(void) {
    int a[210], b[210] = {1}, N, count = 1, t;  // 数组a用于存储用户输入的数值,b数组即是夫妻们围成的圈,N为夫妻的对数,count用于给数组赋值,t是中间值
    while (scanf("%d", &N)) {  // 用循环实现连续赋值
        if (N == 0)  break;   // 当输入值为0时中止循环
        for (int i = 0; i < N*2; i+=2) {  // 用户输值,即夫妻的编号
            scanf("%d%d", &a[i], &a[i+1]);
        }
        for (int i = 1; count < N*2; i++) {  // 利用栈的思想来设计该程序
            if (b[0] == 0) {  // 当第一个数值为0时,要同时给第一第二个数值赋值,避免数组越界,后面就知道了
                count++;
                b[0] = count;
                i++;
            }
            count++;
            b[i] = count;   // 给b数组赋值
            for (int j = 0; j < N*2; j+=2) {  // 用for循环
                if (a[j] > a[j+1]) {  // 把夫妻编号从左到右按从小到大排列,便于找到目标元素
                    t = a[j];
                    a[j] = a[j+1];
                    a[j+1] = t;
                }
                if (a[j] == b[i-1]) {  // 找到目标元素,接下来判断b中相邻两位是否是夫妻。这里对b[i-1]进行操作,有可能导致越界,当i = 0时
                    if (a[j+1] != b[i]) {  // 如果不是夫妻,中止循环
                        break;
                    } else {  // 是夫妻的话,将二者赋为0
                        b[i-1] = 0;
                        b[i] = 0;
                        i = i-2;  // 这里就相当于把刚刚那对夫妻所占的位置消除,即在那对夫妻第一个位置赋值
                        break;
                    }
                }
            }
        }
        if (b[0] != 0)  // 检测数组b,如果全为0,说明全部消除,如果不全为0,说明不能将所有夫妻移走
            printf("No\n");
        else
            printf("Yes\n");
        count = 1;  // 在每次循环结束后,要记得将某些变量进行再次初始化,避免下一个循环受到上一个循环的影响
        b[0] = 1;
        for (int i = 1; i < N*2; i++)
            b[i] = 0;
    }
    return 0;
}

这道题的意思是有N对夫妻,每个人各自有一个编号,即1,2,3….2N,如今将这些编号按顺序围成一个圈,然后我们用户输入夫妻对应的编号,在圆圈中,如果夫妻相邻,就移走,直至全部夫妻移走或者不能再移。能全部移走,输出“Yes”,否则输出“NO”
这道题的难点:

1.对应一个圈我们该如何解决?

显然这道题要用到数组,但数组是直线型的,不能解决一个圈。而圈没有特定的结构解决,因此只有一个办法:把这个圈化为直线。只要这个圈可以全部消除,直线型也可以。因为如果能全部消除,当剩下最后两对时,这两对一定有一对是可以消除的,否则不可能消除,那么这对消除后,最后一对一定能消除,就与他是直线还是圈无关了。

2.那么,我们怎么检测圈中相邻是不是夫妻呢?

这可以用交集的思想,即要一一对应。例如相邻A、B,而夫妻是C、D,我们就证明是否同时满足A == C, B == D.我们可通过循环加个if,找到C夫妻,接着也就找到了D,然后判断二者是否对应相等

3.还有,怎么表示他们移走了呢?

一般来说,我们会想到移走赋值为0,但是这样就会带来很多麻烦:如你要加if将数值为0的元素跳过,而且顺时针逆时针都要判断。
如果我们能够用栈的思想,完成了它的功能后就自动消除,那该多好啊~其实,就是一个一个赋值,当消除了一对夫妻后,就在这对夫妻的第一个位置赋值,这样就类似于消除了间隔,方便很多,而且无需逆时针验证

这道题的易错点:

1.夫妻交换问题:

在用户输入的数据中,左右大小不定,为了方便查找,应将小的放前面,所以做了个交换处理;

2.数组越界问题:

因为我们是在消除的那对夫妻的第一个位置进行赋值,如果刚好第一个元素与第二个元素被消除,那么就在第一个元素上赋值,这样待会在调用赋值元素左边的元素时,就会出现数组越界情况,即取到下标为-1的元素。

3.初始化问题:

其实,对于这种可以测试多组数据的程序,往往要注意初始化。当你第一组数据操作结束后,循环中有些值还是保留着的,这会对下一个循环产生影响,因此要在循环内部的最后面对关键元素进行再次初始化。


以上内容皆为本人观点,欢迎大家批评指出错误,我们一起探讨~


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值