刷紫书第六章例题(例题6-2,6-3,6-6)

例题6-2 Rails UVA - 514

There is a famous railway station in PopPush City. Country there is incredibly hilly. The station
was built in last century. Unfortunately, funds were extremely limited that time. It was possible to
establish only a surface track. Moreover, it turned out that the station could be only a dead-end one
(see picture) and due to lack of available space it could have only one track.
The local tradition is that every train arriving from the direction A continues in the direction
B with coaches reorganized in some way. Assume that the train arriving from the direction A has
N ≤ 1000 coaches numbered in increasing order 1, 2, … , N. The chief for train reorganizations must
know whether it is possible to marshal coaches continuing in the direction B so that their order will
be a1.a2, … , aN . Help him and write a program that decides whether it is possible to get the required
order of coaches. You can assume that single coaches can be disconnected from the train before they
enter the station and that they can move themselves until they are on the track in the direction B. You
can also suppose that at any time there can be located as many coaches as necessary in the station.
But once a coach has entered the station it cannot return to the track in the direction A and also once
it has left the station in the direction B it cannot return back to the station.
Input
The input file consists of blocks of lines. Each block except the last describes one train and possibly
more requirements for its reorganization. In the first line of the block there is the integer N described
above. In each of the next lines of the block there is a permutation of 1, 2, … , N. The last line of the
block contains just ‘0’.
The last block consists of just one line containing ‘0’.
Output
The output file contains the lines corresponding to the lines with permutations in the input file. A line
of the output file contains ‘Yes’ if it is possible to marshal the coaches in the order required on the
corresponding line of the input file. Otherwise it contains ‘No’. In addition, there is one empty line after
the lines corresponding to one block of the input file. There is no line in the output file corresponding
to the last “null” block of the input file.
Sample Input
5
1 2 3 4 5
5 4 1 2 3
0
6
6 5 4 3 2 1
0
0
Sample Output
Yes
No

Yes

【题目思路】
对于一个已经出栈的数,那么小于他的数必然是单调递减的顺序。比如给出的一个出栈结果顺序5 4 2 3 1来说,5是最先出栈的,那么小于5的所有数在5出栈前必须都留在栈里面,又由于1,2,3,4是按照1 2 3 4入栈的,那么出栈顺序必然是4 3 2 1。所以对于出栈结果5 4 2 3 1是不可能 的。请注意入栈顺序一定从1递增的顺序,出栈顺序中必须保证小于某个数的所有尚未出栈的数必须是从大到小依次出栈。
下面给出参考《算法竞赛入门经典》(第2版)的代码。

#include<iostream>
#include<stack>
using namespace std;

const int maxn=1005;
int target[maxn];

int main()
{
    int n;
    while(cin>>n && n){
        while(1){
            cin>>target[1];
            if(target[1]==0) break;
            stack<int>sta;
            for(int i=2;i<=n;i++)
                cin>>target[i];
            int i,j;
            bool flag=1;
            i=j=1;
            while(j<=n){
                if(i==target[j]){i++;j++;}
                else if(!sta.empty() && sta.top()==target[j]){sta.pop();j++;}
                else if(i<=n){sta.push(i++);}
                else{flag=0;break;}
            }
            cout<<(flag?"Yes":"No")<<endl;
        }
        cout<<endl;
    }
    return 0;
}

例题6-3 UVA 442 Matrix Chain Multiplication

Suppose you have to evaluate an expression like A*B*C*D*E where A,B,C,D and E are matrices.
Since matrix multiplication is associative, the order in which multiplications are performed is arbitrary.
However, the number of elementary multiplications needed strongly depends on the evaluation order
you choose.
For example, let A be a 50*10 matrix, B a 10*20 matrix and C a 20*5 matrix. There are two
different strategies to compute A*B*C, namely (A*B)C and A(B*C).
The first one takes 15000 elementary multiplications, but the second one only 3500.
Your job is to write a program that determines the number of elementary multiplications needed
for a given evaluation strategy.
Input
Input consists of two parts: a list of matrices and a list of expressions.
The first line of the input file contains one integer n (1 ≤ n ≤ 26), representing the number of
matrices in the first part. The next n lines each contain one capital letter, specifying the name of the
matrix, and two integers, specifying the number of rows and columns of the matrix.
The second part of the input file strictly adheres to the following syntax (given in EBNF):
SecondPart = Line { Line }
Line = Expression
Expression = Matrix | “(” Expression Expression “)”
Matrix = “A” | “B” | “C” | … | “X” | “Y” | “Z”
Output
For each expression found in the second part of the input file, print one line containing the word ‘error’
if evaluation of the expression leads to an error due to non-matching matrices. Otherwise print one
line containing the number of elementary multiplications needed to evaluate the expression in the way
specified by the parentheses.
Sample Input
9
A 50 10
B 10 20
C 20 5
D 30 35
E 35 15
F 15 5
G 5 10
H 10 20
I 20 25
A
B
C
(AA)
(AB)
(AC)
(A(BC))
((AB)C)
(((((DE)F)G)H)I)
(D(E(F(G(HI)))))
((D(EF))((GH)I))
Sample Output
0
0
0
error
10000
error
3500
15000
40500
47500
15125

【思路】
刚开始想的是映射,把字符映射成结构体,但是当两个字符对应的结构体出栈运算后,再放回到栈里面的时候,问题来了!两个字符怎么表示??没办法了,把栈改成字符串吧,还是会遇到问题,所以此路行不通。所以还是借助《算法竞赛入门经典》(第2版)代码如下:

#include<iostream>
#include<stack>
#include<string>
using namespace std;

struct matrix{
    int row,col;
    matrix(int a=0,int b=0):row(a),col(b){}
}m[30];

stack<matrix>sta;

int main()
{
    int n,row,col;
    char c;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>c>>row>>col;
        m[c-'A'].row=row;
        m[c-'A'].col=col;
    }
    string s;
    while(cin>>s){
        bool flag=1;
        int ans=0;
        for(int i=0;i<s.length();i++){
            if(isalpha(s[i])) sta.push(m[s[i]-'A']);
            else if(s[i]==')'){
                matrix m1=sta.top();sta.pop();
                matrix m2=sta.top();sta.pop();
                if(m2.col!=m1.row){flag=0;break;}
                ans+=m2.row*m2.col*m1.col;
                sta.push(matrix(m2.row,m1.col));
            }
        }
        if(!flag) cout<<"error"<<endl;
        else cout<<ans<<endl;
    }
    return 0;
}

例题6-6 Dropping Balls UVA - 679

A number of K balls are dropped one by one from the root of a fully binary tree structure FBT. Each
time the ball being dropped first visits a non-terminal node. It then keeps moving down, either follows
the path of the left subtree, or follows the path of the right subtree, until it stops at one of the leaf
nodes of FBT. To determine a ball’s moving direction a flag is set up in every non-terminal node with
two values, either false or true. Initially, all of the flags are false. When visiting a non-terminal node
if the flag’s current value at this node is false, then the ball will first switch this flag’s value, i.e., from
the false to the true, and then follow the left subtree of this node to keep moving down. Otherwise,
it will also switch this flag’s value, i.e., from the true to the false, but will follow the right subtree of
this node to keep moving down. Furthermore, all nodes of FBT are sequentially numbered, starting at
1 with nodes on depth 1, and then those on depth 2, and so on. Nodes on any depth are numbered
from left to right.
For example, Fig. 1 represents a fully binary tree of maximum depth 4 with the node numbers 1,
2, 3, …, 15. Since all of the flags are initially set to be false, the first ball being dropped will switch
flag’s values at node 1, node 2, and node 4 before it finally stops at position 8. The second ball being
dropped will switch flag’s values at node 1, node 3, and node 6, and stop at position 12. Obviously,
the third ball being dropped will switch flag’s values at node 1, node 2, and node 5 before it stops at
position 10.
Fig. 1: An example of FBT with the maximum depth 4 and sequential node numbers.
Now consider a number of test cases where two values will be given for each test. The first value is
D, the maximum depth of FBT, and the second one is I, the I-th ball being dropped. You may assume
the value of I will not exceed the total number of leaf nodes for the given FBT.
Please write a program to determine the stop position P for each test case.
For each test cases the range of two parameters D and I is as below:
2 ≤ D ≤ 20, and 1 ≤ I ≤ 524288.
Input
Contains l + 2 lines.
Line 1 l the number of test cases
Line 2 D1 I1 test case #1, two decimal numbers that are separated by one blank

Line k + 1 Dk Ik test case #k
Line l + 1 Dl Il test case #l
Line l + 2 -1 a constant ‘-1’ representing the end of the input file
Output
Contains l lines.
Line 1 the stop position P for the test case #1

Line k the stop position P for the test case #k

Line l the stop position P for the test case #l
Sample Input
5
4 2
3 4
10 1
2 2
8 128
-1
Sample Output
12
7
512
3
255

超时代码(直接模拟):

//不是针对此题的提示:C++流和STL速度都会减慢,一般能不用
//就不用,用C语言写这些题目比较稳

#include<cstdio>
#include<cstring>

const int maxn=20;
int sta[(1<<maxn)+5];//注意这里移位加括号

int main()
{
    int t;
    while(scanf("%d",&t)!=EOF && t!=-1){
        while(t--){
            int d,n,cnt=1;
            scanf("%d%d",&d,&n);
            int sum=(1<<d)-1;//注意这里的括号
            memset(sta,0,sizeof(sta));
            for(int i=0;i<n;i++){
                cnt=1;
                while(1){
                    sta[cnt]=!sta[cnt];
                    cnt=(sta[cnt]?(2*cnt):(2*cnt+1));
                    if(cnt>sum) break;
                }
            }
            printf("%d\n",cnt/2);
        }
    }
    return 0;
}

上述代码超时,因为一是输入数据可能量比较大,再加上本题是2的指数次方的量级!

【分析思考】
我们可以分析编号是1,2,3,4,5,6,7,8这8个球,找规律,手画一下二叉树,写出每个结点上经过的所有球,其实,对于每个结点上的球来说,下一步走向左子树还是右子树取决于他是第几个来到该结点的。对根结点来说,第奇数个来到根结点的球必然走向左子树,第偶数个来到根结点的球必然走向右子树。再看左子树的根结点,与上类似,第奇数个来到左子树的根结点的球必然走向左子树的左子树,第偶数个来到左子树的根结点的球必然走向左子树的右子树,依次类似。
对于第n个球来说,他是第n个来到根结点的球,如果是n是奇数,他走向左子树,如果n是偶数,他走向右子树。以n是奇数为例,第n个球走向左子树的根结点,算上之前走过左子树的根结点的球,一共有(n+1)/2个,在这么多个球中,第n个球是第(n+1)/2个来到左子树的根结点,如果,(n+1)/2是奇数,则第n个球必然继续走向下一层的左子树,否则走向右子树。就这样,依次类推即可。解题核心就这些。

下面代码参考刘汝佳《算法竞赛入门经典》(第2版)

#include<cstdio>

int main()
{
    int t;
    while(scanf("%d",&t)!=EOF && t!=-1){
        while(t--){
            int d,n,cnt=1;
            scanf("%d%d",&d,&n);
            //模拟最后一个球的路线(不是该球,是该球的路线)d-1次的结果就是其落下的编号
                //这一点可以假设d=2就想明白了
            //对于每个结点来说,如果是第偶数个来的球,必然走向他的右子树,如果是第奇数个
            //来的球,必然走向他的左子树
            for(int i=0;i<d-1;i++){
                if(n%2) {cnt=cnt*2;n=(n+1)/2;}//如果n是奇数,则第n个球是第(n+1)/2个来到下一个左子树的根结点的球
                else {cnt=cnt*2+1;n=n/2;}//如果n是偶数,则第n个球是第n/2个来到下一个右子树的根结点的球
                                        //更新后的n始终是对应经过某结点上球的个数,且更新后的第n个球选择左走还是右走仍然是起初
                                        //第n个球的选择
            }
            printf("%d\n",cnt);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值