1. 程式人生 > 實用技巧 >北京大學ACM-ICPC競賽訓練暑期課

北京大學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