暑假学习报告总结
暑假期间,自学了一部分的acm的算法,了解了一些acm的知识点,虽然并不是每一章都手动敲过代码,但是也粗略的看了算法竞赛入门到进阶的大概内容。虽然都是自学,但是学校的老师也安排了一些比赛和题目供我们学习和练习,虽然比赛基本上做不出几道题,但是也稍微了解了acm的比赛和难度。
在暑假期间,我比较着重学习了容器,并查集,二叉树,背包dp,哈希,bfs,dfs,贪心。虽然学得不是很精,但是基本上都刷过一些题,以下通过一些我做过的题目来巩固和理解这些算法。
因为在大一时学习了bfs和dfs,以及贪心,因此以下不作讨论。
1 容器
Stl俗称标准库,有很多好用的容器,而且在某些题中有着十分优秀的作用,例如在求一些数组长度需要不断变化的情况下,vector,map,queue,stack可以起到十分好的帮助。
约瑟夫环问题
#include<bits/stdc++.h>
using namespace std;
vector<int>a;
int n,m;
int main(){
while(cin>>n>>m){
a.clear();
for(int i=0;i<n;i++)a.push_back(i);//初始化
int pos=0;
for(int i=0;i<n-1;i++){
pos=(pos+m-1)%a.size();
a.erase(a.begin()+pos);
}
printf("%d",a[0]+1);
}
}
在另一道题中,set也有着十分优秀的作用
产生冠军 hdu 1276
#include<bits/stdc++.h>
using namespace std;
int main()
{int n;
string s1,s2;
while(cin>>n&&n){
set<string>a,b;//创建集合
for(int i=0;i<n;i++){
cin>>s1>>s2;
a.insert(s1);//插入数据
a.insert(s2);
b.insert(s2);
}
if(a.size()-b.size()==1)cout<<"Yes"<<endl;//判断集合大小
else cout<<"No"<<endl;
a.clear();b.clear(); //清空集合
}
}
这道题是书上的例题,但是这道题很好的运用了set里不能存相同的数据的特点。
2 并查集
从并查集开始,基本上代码量就上来了,并查集类似于找朋友,一般先初始化,然后合并,最后查找有多个集。
Ubiquitous Religions
Poj 2524
#include<iostream>
using namespace std;
const long long maxn=50000+5;
long long int s[maxn];
void init(){
for(int i=1;i<=maxn;i++){
s[i]=i;
}
}
int find(int x){
return x==s[x]?x:find(s[x]);
}
void union_1(int x,int y){
x=find(x);
y=find(y);
if(x!=y)s[x]=s[y];
return;
}
int main(){
int m,n,x,y;
int cnt=0;
while(cin>>n>>m,n,m){
init();
for(int i=1;i<=m;i++)
{
cin>>x>>y;
union_1(x,y);
}
int count=0;
for(int i=1;i<=n;i++){
if(s[i]==i)count++;
}
cout<<"Case "<<++cnt<<": "<<count<<endl;
}
}
这道典型的并查集,实际上还可以在合并上优化和路径上优化,能够在某些情况下更快一点,不过在这道题上,并不需要。
Poj 1703
#include <iostream>
#include<stdio.h>
using namespace std;
const int N = 100000+100;
int f[N], num[N];
int n, m;
void init() {
for (int i = 1; i <= n; i++) {
f[i] = i;
num[i] = 1;
}
}
int find(int x) {
if(f[x]==x)
return x;
int tem=f[x];
f[x]=find(f[x]);
num[x]=(num[x]+num[tem]+1)%2;
return f[x];
}
void Union(int a, int b) {
int c=find(a);
int d=find(b);
if(c!=d)
{
f[c]=d;
num[c]=(num[a]+num[b])%2;
}
}
int main() {
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
init();
char ch;
int j,k;
while(m--){
scanf("%c%d%d",&ch,&j,&k);
if(ch=='A'){
int a=find(j);
int b=find(k);
if(a!=b)
printf("Not sure yet.\n");
else if(num[j]==num[k])
printf("In the same gang.\n");
else
printf("In different gangs.\n");
}
else if(ch=='D'){
Union(j,k);
}
}
}
return 0;
// system("pause");
}
这道题便是典型的超时了,差一点点。
3 哈希
哈希是一种牺牲空间换时间的方法
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000001;
int a[maxn];
int n,m;
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<n;i++){
int t;
scanf("%d",&t);
a[500000+t]=1;
}
for(int i=maxn;m>0;i--){
if(a[i]==1){
if(m>1)printf("%d ",i-500000);
else printf("%d\n",i-500000);
m--;
}}}
}
0(n)的时间复杂度,不过在有相同的数时,这道程序不能判断。
4 背包
跑楼梯问题,每次能选择怕一次或者2次
#include<iostream>
using namespace std;
int a[1001];
int fun(int n)
{ a[1]=1;
a[0]=1;
for(int i=2;i<=n;i++)
a[i]=a[i-1]+a[i-2];//a[2]=a[1]+a[0]
return a[n];
}
int main()
{
int k;
cin>>k;
int b=fun(k);
cout<<b<<endl;
}
很好的体现了dp的思想。
总结:
实际上acm算法还有数学,图论,几何,但是因为在暑假期间,学习了一些其它计算机知识,也就没有仔细研究了。虽然有初步了解,但是做题还是不太会,新学期了,时间相比上学期来说,学业更重了一些,但是学习算法的道路不会因此停止。