北京大学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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
冰阔落 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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
开餐馆
描述
北大信息学院的同学小明毕业之后打算创业开餐馆.现在共有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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
输出前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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
滑雪
描述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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }