春季个人训练赛-6

1、 Bit String Reordering

You have to reorder a given bit string as specified. The only operation allowed is swapping adjacent
bit pairs. Please write a program that calculates the minimum number of swaps required.
The initial bit string is simply represented by a sequence of bits, while the target is specified by a
run-length code. The run-length code of a bit string is a sequence of the lengths of maximal consecutive
sequences of zeros or ones in the bit string. For example, the run-length code of “011100” is “1 3 2”.
Note that there are two different bit strings with the same run-length code, one starting with zero and
the other starting with one. The target is either of these two.
In Sample Input 1, bit string “100101” should be reordered so that its run-length code is “1 3 2”,
which means either “100011” or “011100”. At least four swaps are required to obtain “011100”. On the
other hand, only one swap is required to make “100011”. Thus, in this example, 1 is the answer.

Input
The input file contains several test cases, each of them as described below.
Each test case is formatted as follows.
N M
b1 b2 . . . bN
p1 p2 . . . pM

The first line contains two integers N (1 ≤ N ≤ 15) and M (1 ≤ M ≤ N). The second line specifiesthe initial bit string by N integers. Each integer bi is either ‘0’ or ‘1’. The third line contains the run-length code, consisting of M integers. Integers p1 through pM represent the lengths of consecutive sequences of zeros or ones in the bit string, from left to right. Here, 1 ≤ pj for 1 ≤ j ≤ M and∑Mj=1 pj = N hold. It is guaranteed that the initial bit string can be reordered into a bit string withits run-length code p1, . . . , pM.
Output
For each test case, output the minimum number of swaps required.
Sample Input
6 3
1 0 0 1 0 1
1 3 2

7 2
1 1 1 0 0 0 0
4 3

15 14
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 2

1 1
0
1

Sample Output
1
12
7
0

题意:
给定由0和1组成的字符串,然后把它变成规定长度的字符串,只能交换相邻的,问需要交换几次?
看样例:
1 0 0 1 0 1
1 3 2

首先 1 3 2 代表连续字符的长度,可以是:
1 0 0 0 1 1 或者  0 1 1 1 0 0
由样例到这两种字符串,需要交换的步数分别是:1 4 次,那么交换最少的肯定是1次

思路:
我的思路是根据长度然后构造出两种形式的字符串
一个是1开头,一个是0开头的
首先先排除一些不符合题意的情况,比如说:
1 1 1 0 0 0 0
4 3
根据 4 3 构造出两种:
1 1 1 1 0 0 0  或者 0 0 0 0 1 1 1
然后可以排除掉第1种,因为第一种的1的个数已经超过了原有字符串的个数

如果不符合上述,留下的就是两种情况都满足的情况,那么只需要取最小值即可

例如  
1 1 1 0 0 0 0 
4 3

根据上述判断,只有  0 0 0 0 1 1 1 满足
a: 1 1 1 0 0 0 0
b: 0 0 0 1 1 1 1
首先第一个找到的是第一位的1和0不一样,那么就需要交换这一位
a中的字符是1,只需要找一个和1不同的,并且a、b该位不同的即可
就是第四位的0,同时把第四位的0换成和第一位相同的数字,防止下一次找到的还是他,以防重复考虑

由于只能相邻的交换,那么交换的次数就是   4 - 1 = 3 次
下一次就是第二位的1,然后找到的是第五位的0,交换3次,同时把第五位的0变成1

CODE:
自己代码写的有点太复杂啦,有可以合并在一起的地方,比赛的时候想起就写了,没有想到优化一下代码

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
typedef long long LL;
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define INF 0x3f3f3f3f

int main()
{
    int n,m;
    int a[20];
    int b[20],c[20],d[20];
    int x[3];
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        int flag=0;
        memset(x,0);
        memset(a,0);
        memset(b,0);
        memset(d,0);
        memset(c,0);

        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
            if(a[i]==0)
                x[0]++;
            else
                x[1]++;
        }

        //cout<<x[0]<<'*'<<x[1]<<endl;

        for(int i=0; i<m; i++)
            scanf("%d",&b[i]);

        int cnt=0,aa=0,bb=0;
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<b[i]; j++)
            {
                if(i%2)
                {
                    c[cnt++]=0;
                    aa++;
                }
                else
                {
                    c[cnt++]=1;
                    bb++;
                }
            }
        }

        int cnt1=0,a1=0,b1=0;
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<b[i]; j++)
            {
                if(i%2)
                {
                    d[cnt1++]=1;
                    b1++;
                }
                else
                {
                    d[cnt1++]=0;
                    a1++;
                }
            }
        }

        if(aa>x[0]||bb>x[1])
            flag=1;
        if(a1>x[0]||b1>x[1])
            flag=2;

        int ans=0;
        //cout<<flag<<endl;
        if(flag==1)
        {
            for(int i=0; i<n; i++)
            {
                if(d[i]!=a[i])
                {
                    for(int j=i+1; j<n; j++)
                    {

                        if(d[j]!=a[j]&&d[j]!=d[i])
                        {
                            int k=j-i;
                            //cout<<i<< ' '<<j<<' '<<endl;
                            ans+=k;
                            if(d[i]==0)
                                d[j]=0;
                            else
                                d[j]=1;
                            break;
                        }
                    }
                }
            }
            cout<<ans<<endl;
            continue;

        }

        if(flag==2)
        {
            for(int i=0; i<n; i++)
            {
                if(c[i]!=a[i])
                {
                    for(int j=i+1; j<n; j++)
                    {

                        if(c[j]!=a[j]&&c[j]!=c[i])
                        {
                            int k=j-i;
                            ans+=k;
                            if(c[i]==0)
                                c[j]=0;
                            else
                                c[j]=1;
                            break;
                        }
                    }
                }
            }

            cout<<ans<<endl;
            continue;
        }


        for(int i=0; i<n; i++)
        {
            if(d[i]!=a[i])
            {
                for(int j=i+1; j<n; j++)
                {

                    if(d[j]!=a[j]&&d[j]!=d[i])
                    {
                        int k=j-i;
                        //cout<<i<< ' '<<j<<' '<<endl;
                        ans+=k;
                        if(d[i]==0)
                            d[j]=0;
                        else
                            d[j]=1;
                        break;
                    }
                }
            }
        }

        int ans1=0;
        for(int i=0; i<n; i++)
        {
            if(c[i]!=a[i])
            {
                for(int j=i+1; j<n; j++)
                {

                    if(c[j]!=a[j]&&c[j]!=c[i])
                    {
                        int k=j-i;
                        ans1+=k;
                        if(c[i]==0)
                            c[j]=0;
                        else
                            c[j]=1;
                        break;
                    }
                }
            }
        }


        int minn=min(ans,ans1);
        cout<<minn<<endl;
    }
}

2、 Miscalculation
Bob is an elementary schoolboy, not so good at mathematics. He found Father’s calculator and tried
cheating on his homework using it. His homework was calculating given expressions containing multiplications
and additions. Multiplications should be done prior to additions, of course, but the calculator
evaluates the expression from left to right, neglecting the operator precedence. So his answers may be
the result of either of the following two calculation rules.
• Doing multiplication before addition
• Doing calculation from left to right neglecting the operator precedence
Write a program that tells which of the rules is applied from an expression and his answer.
An expression consists of integers and operators. All the integers have only one digit, from 0 to 9.
There are two kinds of operators ‘+’ and ‘*’, which represent addition and multiplication, respectively.

The following is an example expression.
1+2*3+4
Calculating this expression with the multiplication-first rule, the answer is 11, as in Sample Input

  1. With the left-to-right rule, however, the answer will be 13 as shown in Sample Input 2. There may
    be cases in which both rules lead to the same result and you cannot tell which of the rules is applied.
    Moreover, Bob sometimes commits miscalculations. When neither rules would result in Bob’s answer,
    it is clear that he actually did.

Input
The input file contains several test cases, each of them as described below.
Each test case is specified with two lines. The first line contains the expression to be calculated.
The number of characters of the expression is always odd and less than or equal to 17. Each of the oddnumbered
characters in the expression is a digit from ‘0’ to ‘9’. Each of the even-numbered characters is
an operator ‘+’ or ‘*’. The second line contains an integer which ranges from 0 to 999999999, inclusive.
This integer represents Bob’s answer for the expression given in the first line.

Output
For each test case, output one of the following four characters:
M — When only the multiplication-first rule results Bob’s answer.
L — When only the left-to-right rule results Bob’s answer.
U — When both of the rules result Bob’s answer.
I — When neither of the rules results Bob’s answer.

Sample Input
1+23+4
11
1+2
3+4
13
3
3
1+2*3+4
9

Sample Output
M
L
U
I

题意:
给定一个算术表达式,然后给一个结果 ans
可以有以下算法
1、先算乘法,再算加减( 输出 M)
2、从左往右算,不考虑优先级( 输出 L )
3、既满足乘法也满足从左往右算( 输出 U)
  这个U的情况,有点特殊
  单个的一个数字、连乘、连加、乘法比加法先出现
  以上都输出U
  (这都是WA了六次得出的教训)
  不用专门考虑这么多情况,只要是以上两种得到的结果相同就满足U
4、123都不满足( 输出 I)

思路:
求12结果的方法:
1、利用了栈求算术表达式的原理
  如果是数字放入数组中
  是加号不用考虑
  如果是乘号的话,需要将数组中最末的数字和乘号的下一位相乘,将结果放入数组中
  最后将数组中的数字累加求和即可
2、是加号,将上一步的结果与下一个数字相加,是乘号就相乘
  需要注意,ans 一开始初始化为第一个数字
 
CODE:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
typedef long long LL;
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define INF 0x3f3f3f3f

int main()
{
    char s[20];
    LL m;

    while(scanf("%s",s)!=EOF)
    {
        scanf("%lld",&m);

        int len=strlen(s);
        if(len==1)
        {
            LL k=s[0]-'0';
            if(k==m)
            {
                cout<<"U"<<endl;
                continue;
            }

            cout<<"I"<<endl;
            continue;
        }

        LL ans=s[0]-'0';
        for(int i=0;i<len;i++){
            if(s[i]=='+'&&i!=0&&i!=len-1){
                LL k=ans+(s[i+1]-'0');
                ans=k;
            }

            if(s[i]=='*'&&i!=0&&i!=len-1){
                LL k=ans*(s[i+1]-'0');
                ans=k;
            }
        }

//cout<<ans<<endl;


        LL ans1=0;
        int c[20];
        int cnt=0;
        for(int i=0;i<len;i++){
            if(s[i]>='0'&&s[i]<='9')
                c[cnt++]=s[i]-'0';

            if(s[i]=='*'){
                int k=s[i+1]-'0';
                s[i+1]='a';
                k=k*c[cnt-1];
                c[cnt-1]=k;
            }
        }

        for(int i=0;i<cnt;i++)
            ans1+=c[i];

       /// cout<<ans1<<endl;

        if(m==ans&&m==ans1)
        {
            cout<<"U"<<endl;
            continue;
        }

        if(m==ans)
        {
            cout<<"L"<<endl;
            continue;
        }

        if(m==ans1){
            cout<<"M"<<endl;
            continue;
        }

        cout<<"I"<<endl;
    }
}

3、 Shopping

Your friend will enjoy shopping. She will walk through a mall along a straight street, where N individual
shops (numbered from 1 to N) are aligned at regular intervals. Each shop has one door and is located
at the one side of the street. The distances between the doors of the adjacent shops are the same length,
i.e. a unit length. Starting shopping at the entrance of the mall, she visits shops in order to purchase
goods. She has to go to the exit of the mall after shopping.
She requires some restrictions on visiting order of shops. Each of the restrictions indicates that she
shall visit a shop before visiting another shop. For example, when she wants to buy a nice dress before
choosing heels, she shall visit a boutique before visiting a shoe store. When the boutique is farther
than the shoe store, she must pass the shoe store before visiting the boutique, and go back to the shoe
store after visiting the boutique.

If only the order of the visiting shops satisfies all the restrictions, she can visit other shops in any
order she likes.
Write a program to determine the minimum required walking length for her to move from the
entrance to the exit.
Assume that the position of the door of the shop numbered k is k units far from the entrance, where
the position of the exit is N + 1 units far from the entrance.
Input
The input file contains several test cases, each of them as described below.
Each case input consists of a set of lines.
N m
c1 d1
.
.
.
cm dm
The first line contains two integers N and m, where N (1 ≤ N ≤ 1000) is the number of shops, and
m (0 ≤ m ≤ 500) is the number of restrictions. Each of the next m lines contains two integers ci and
di (1 ≤ ci < di ≤ N) indicating the i-th restriction on the visiting order, where she must visit the shop
numbered ci after she visits the shop numbered di (i = 1, . . . , m).
There are no pair of j and k that satisfy cj = ck and dj = dk.

Output
For each test case, output the minimum required walking length for her to move from the entrance to
the exit. You should omit the length of her walk in the insides of shops.

Sample Input
10 3
3 7
8 9
2 5
10 3
8 9
6 7
2 4
10 0
10 6
6 7
4 5
2 5
6 9
3 5
6 8
1000 8
3 4
6 1000
5 1000
7 1000
8 1000
4 1000
9 1000
1 2

Sample Output
23
19
11
23
2997

题意:
给n个商店,其中某些商店i必须在j之后才能访问(j>i)
每个商店之间有相同的距离,设单位长度1
只能按照顺序走,并且得访问完j才能访问i,问走到出口需要的最少步数是多少?

思路:
我用了 father[] ,记录i的父亲节点是j,代表需要访问完j才能访问i(初始化的时候父亲节点为自己)
思路是这样的:
看下图的样例
10 6
6 7
4 5
2 5
6 9
3 5
6 8

ans:23

思路:

1、对父亲节点进行标记,方便找到;
2、记录下来需要访问的商店(i)的个数(sum),然后找到相对应个数(sum)的父亲节点(j),从j开始返回过去,就可以把商店(i)给访问完;
3、如果一个商店有多个父亲节点,那么保留他的最大值(只有他的父亲节点都访问了才可以访问该商店)
4、在找 sum的时候,如果这个商店的父亲节点 大于 前一个父亲节点,则用这一个替换前一个的父亲节点

例如:
当走到2的时候,发现其父亲节点不是他自己,代表了需要访问完j才能访问2,把其父亲节点(5)记录下来,然后就一直往前走,走到3,发现父亲节点不是自己,其父亲节点是5和2的父亲节点是一样的,所以此时的计数(sum)是不变的;

解释为什么不变:
因为23的父亲节点都是5,此时记录下来需要找的父亲节点个数是1,当你找到5的时候,就可以把23都访问了;
如果不这样做,就是需要去找两个父亲节点,当你找到5的时候,还缺一个就往前找到了7,但此时并不是最短的步数 

然后往前走找到了4号,其父亲节点仍是5,则计数(sum)不变,还是1个,往前走发现5被标记了,代表的是一个父亲节点,找到了一个就是5,然后返回,234号就都可以访问了

找完5之后,接着往后走,发现6的父亲节点是9(因为他有两个最大的,所以父亲节点保留最大的)
然后重新重复上一次的步骤,记得初始化

在这里插入图片描述

CODE:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
typedef long long LL;
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define INF 0x3f3f3f3f

int father[1005];
int vis[1005];
void init()
{
    for(int i=0;i<=1002;i++)
        father[i]=i;
}

int main()
{
    int n,m,a,b;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        init();
        memset(vis,0);
        int pos=1;
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&a,&b);
            if(b>father[a]){
                father[a]=b;
            }
            vis[b]=1;
        }

        int maxx=-1;
        int minn=INF;

        int ans=n+1; // 这个1-n的距离n+1肯定要走的
        int sum=0,sum1=0;
        int flag=1;
        pos=0;
        for(int i=1;i<=n;i++)
        {

			// 从前往后走的时候,如果找到了这个最大的父亲节点,就说明这一次可以返回了
            if(father[i]==maxx){
                // 返回再回来,双向的
                yaochushihuaint k=(i-minn)*2;
             
                ans+=k;
               //  这一次结束了,接着去找一次类似此过程的,计数要初始化
                sum=0;
                sum1=0;
                flag=1;
                minn=INF;
                maxx=-1;
            }

            if(father[i]!=i)
            {
                // 这一个是记录这一次过程的第一个商店的坐标,方便返回到该点
                if(flag==1){
                    pos=i;
                    sum=vis[i];
                }
                minn=min(minn,pos);
                //cout<<minn<<endl;
                flag=0;
				// 记录父亲节点的最大值
                maxx=max(father[i],maxx);
                if(father[i]==maxx)
                    sum=1;
               // 代表需要多找一个商店
                if(father[i]>maxx)
                    sum++;
            }

        }

        cout<<ans<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/JKdd123456/article/details/88627313