北京大学ACM-ICPC竞赛训练暑期课

全排列 (递归DFS)

描述

给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。 我们假设对于小写字母有'a' < 'b' < ... < 'y' < 'z',而且给定的字符串中的字母已经按照从小到大的顺序排列。

输入输入只有一行,是一个由不同的小写字母组成的字符串,已知字符串的长度在1到6之间。输出输出这个字符串的所有排列方式,每行一个排列。要求字母序比较小的排列在前面。字母序如下定义:

已知S = s1s2...sk , T = t1t2...tk,则S < T 等价于,存在p (1 <= p <= k),使得
s1 = t1, s2 = t2, ..., sp - 1 = tp - 1, sp < tp成立。样例输入

abc

样例输出

abc
acb
bac
bca
cab
cba

 

#include <bits/stdc++.h>
using namespace std;
string str,sub;
int a[50000+5],cnt=0,n;
string ch[720];
void dfs(int k,string &sub)
{

    //cout<<k<<endl;
    if(k==n)
    {
        cout<<sub<<endl;
        return ;
    }
    for(int i=0;i<n;i++)
    {
        if(!a[i])
        {
            string xx;
            xx=sub;
            sub+=str[i];
            a[i]=1;cnt++;
            dfs(cnt,sub);
            a[i]=0;cnt--;
            sub=xx;
        }
    }
}
int main()
{
    int m,l,r;
    cin>>str;
    memset(a,0,sizeof(a));
    n= str.size();
    sub="";
    dfs(cnt,sub);
    return 0;

}
View Code

冰阔落 I

描述

老王喜欢喝冰阔落。

初始时刻,桌面上有n杯阔落,编号为1到n。老王总想把其中一杯阔落倒到另一杯中,这样他一次性就能喝很多很多阔落,假设杯子的容量是足够大的。

有m 次操作,每次操作包含两个整数x与y。

若原始编号为x 的阔落与原始编号为y的阔落已经在同一杯,请输出"Yes";否则,我们将原始编号为y 所在杯子的所有阔落,倒往原始编号为x 所在的杯子,并输出"No"。

最后,老王想知道哪些杯子有冰阔落。

 

输入有多组测试数据,少于 5 组。
每组测试数据,第一行两个整数 n, m (n, m<=50000)。接下来 m 行,每行两个整数 x, y (1<=x, y<=n)。
输出每组测试数据,前 m 行输出 "Yes" 或者 "No"。
第 m+1 行输出一个整数,表示有阔落的杯子数量。
第 m+2 行有若干个整数,从小到大输出这些杯子的编号。
样例输入

3 2
1 2
2 1
4 2
1 2
4 3

样例输出

No
Yes
2
1 3 
No
No
2
1 4


#include <bits/stdc++.h>
using namespace std;
string str;
int a[50000+5],cnt;
int root(int x)
{
    if(a[x]==x) return x;
    return root(a[x]);
}
void find(int l,int r)
{
    int ll=root(l),rr=root(r);
    if(ll==rr)
    {
        printf("Yes\n");
        //cout<<"Yes"<<endl;
    }
    else
    {
        a[rr] =ll;
        cnt--;
        //cout<<"No"<<endl;
        printf("No\n");
    }
}
int main()
{
    int m,n,l,r;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        cnt=n;
        for(int i=1;i<=n;i++)
        {
            a[i]=i;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&l,&r);
            //cin>>l>>r;
            find(l,r);
        }
        printf("%d\n",cnt);
        //cout<<cnt<<endl;
        for(int i=1;i<=n;i++)
            if(a[i]==i) printf("%d ",i);//cout<<i<<" ";
        //cout<<endl;
        printf("\n");
    }
    return 0;

}
View Code

开餐馆

描述

北大信息学院的同学小明毕业之后打算创业开餐馆.现在共有n 个地点可供选择。小明打算从中选择合适的位置开设一些餐馆。这 n 个地点排列在同一条直线上。我们用一个整数序列m1, m2, ... mn 来表示他们的相对位置。由于地段关系,开餐馆的利润会有所不同。我们用pi 表示在mi 处开餐馆的利润。为了避免自己的餐馆的内部竞争,餐馆之间的距离必须大于k。请你帮助小明选择一个总利润最大的方案。

 

输入标准的输入包含若干组测试数据。输入第一行是整数T (1 <= T <= 1000) ,表明有T组测试数据。紧接着有T组连续的测试。每组测试数据有3行,
第1行:地点总数 n (n < 100), 距离限制 k (k > 0 && k < 1000).
第2行:n 个地点的位置m1 , m2, ... mn ( 1000000 > mi > 0 且为整数,升序排列)
第3行:n 个地点的餐馆利润p1 , p2, ... pn ( 1000 > pi > 0 且为整数)输出对于每组测试数据可能的最大利润样例输入

2
3 11
1 2 15
10 2 30
3 16
1 2 15
10 2 30

样例输出

40
30

#include <bits/stdc++.h>
using namespace std;
int dp[100+5];
struct node 
{
    int v,h;
} no[100+5];
int main()
{
    int t,n,m;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            scanf("%d",&no[i].v );
        for(int i=1;i<=n;i++)
            scanf("%d",&no[i].h );
        if(m>no[n].v)
        {
            int mx=-1000;
            for(int i=1;i<=n;i++)
                mx=max(no[i].h,mx);
            printf("%d\n",mx);
        }
        else
        {
            for(int i=1;i<=n;i++)
            {
                dp[i] = no[i].h;
                int mx = no[i].v , mk = no[i].h ;    
                for(int j=1;j<i;j++)
                {
                    if( no[i].v - no[ j ].v > m )
                    {
                        dp[ i ] = max( dp[i] ,dp[j] + mk );
                    }
                        
                }
            }
            cout<<*max_element(dp+1,dp+n+1)<<endl;    
        }
        
    }
    return 0;
}
View Code

输出前k大的数

描述

给定一个数组,统计前k大的数并且把这k个数从大到小输出。

输入第一行包含一个整数n,表示数组的大小。n < 100000。
第二行包含n个整数,表示数组的元素,整数之间以一个空格分开。每个整数的绝对值不超过100000000。
第三行包含一个整数k。k < n。输出从大到小输出前k大的数,每个数一行。样例输入

10
4 5 6 9 8 7 1 2 3 0
5

样例输出

9
8
7
6
5

#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
using namespace std;
int n,k;
int a[100000+5];
void find(int l,int r,int ans)
{
    if(l>=r) return ;
    int ll=l,rr=r;
    while(l!=r)
    {
        while(l<r && a[l]<=a[r]) r--;
        swap(a[l],a[r]);
        while(l<r && a[l]<=a[r]) l++;
        swap(a[l],a[r]);
    }
    if(rr-l+1 == ans) return ;
    rr-l+1 < ans  ? find(ll,l-1,ans-(rr-l+1))  :find(l+1,rr,ans);
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)    cin>>a[i];
    cin>>k;
    find(0,n-1,k);
    sort(a+n-k,a+n);
    for(int t=n-1;t>=n-k;t--)
        cout<<a[t]<<endl;    
    return 0;
}
View Code

滑雪 

描述Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子

 1  2  3  4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9


一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。输入输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。输出输出最长区域的长度。样例输入

5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9

样例输出

25
#include <bits/stdc++.h>
using namespace std;

int dir[4][2]={-1,0,0,1,1,0,0,-1};
int a[101][101],len[101][101];
int n,m;
int dfs(int x,int y)
{
    if(len[x][y]) return len[x][y];
    int mx=0,s;
    for(int i=0;i<4;i++)
    {
        int nx=x+dir[i][0],ny=y+dir[i][1];
        if(nx>=0 && nx<n && ny>=0 && ny<m && a[nx][ny] < a[x][y])
        {
            s=dfs(nx,ny);
            if(s>mx)
                mx=s;
        }
    }
    
    return len[x][y] = mx+1;
}
int main()
{
    int mx=-1;
    cin>>n>>m;
    memset(len,0,sizeof(len));
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin>>a[i][j];
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(dfs(i,j) > mx)
                mx=len[i][j];
    cout<<mx<<endl;
    return 0;
}
View Code

 

posted @ 2020-10-05 12:44  __MEET  阅读(521)  评论(0编辑  收藏  举报