简单散列表例题和简单DFS例题

洛谷:简单模拟


P1056排座椅

点击查看题目描述

该题运用了散列表的思想对数据进行存储

什么是散列表?

散列表Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。 ——维基百科

  • 若关键字为k,则其值存放在 f(k) 的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系 f 为散列函数,按这个思想建立的表为散列表
#include
using namespace std;
struct  node{
	int guodao;
	int count;
};
node a[2500]={},b[2500]={};//初始化,变量全为0
inline int cmp2(node n1,node n2){
	return n1.guodao<n2.guodao; 
}
bool cmp(node x,node y)
{
	return x.count>y.count;
}
int main()
{
	int M,N,K,L,D;//分别代表教室有M行N列
	cin>>M>>N>>K>>L>>D;//K条横向通道,L条纵向通道;D对讲话的同学
	int cntl,cntk;
	int e=0,f=0;
	for(int i=0;i<D;i++)
	{
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;	
		if(x1==x2)	//如果横坐标相等,则选择纵轴偏小的作为过道
		{
			cntl=(y1<y2)?y1:y2;
			b[cntl].guodao=cntl;//存储在cntl处
			b[cntl].count++;	
		}
		else if(y1==y2)	//如果纵坐标相等,则选择横轴偏小的作为过道
		{
			cntk=(x1<x2)?x1:x2;
			a[cntk].guodao=cntk; //存储在cntk处
			a[cntk].count++;
		}
	}
    //按照过道选择次数降序排列
	sort(a,a+M,cmp);
	sort(b,b+N,cmp);
    //按照过道数字大小升序排列
	sort(a,a+K,cmp2);
	sort(b,b+L,cmp2);
	for(int i=0;i<K;i++)
		cout<<a[i].guodao<<" ";	
	cout<<endl;
	for(int i=0;i<L;i++)
		cout<<b[i].guodao<<" ";	
	return 0;
}

P1540机器翻译

点击查看题目详情

看到题目我就想到队列,不过我是直接用数组模拟队列,而知道STL的选手们直接使用queue

以下是这两种思想的不同代码,不得不说一句STL万岁!

手动模拟:

#include
using namespace std;

bool searchin(int num,int M,int m[])
{
	bool k=false;
	for(int i=0;i<M;i++)
	{
		if(num==m[i])
		{
			k=true;
			break;	
		}
	}
	return k;
}
int main()
{
	int cnt;//计数 
	int M,N;
	cin>>M>>N;
	int m[M],n[N];	
	memset(m,-1,sizeof(m));
	for(int i=0;i<N;i++)
	{
		cin>>n[i];
		if(!searchin(n[i],M,m))
		{
			cnt++;
			for(int j=1;j<M;j++)
				m[j-1]=m[j];
			m[M-1]=n[i];
		}
	}
	cout<<cnt;
	return 0;
}

STL:queque

#include
#include
#include
using namespace std;
queue<int>s;
int main()
{
	int m,word,count=0,f[1010]={0};
	cin >> m >> word;
	for(int i = 0; i<word; i++)
	{
		int x;
		cin>>x;
		if(f[x]==1)continue;	    
		else 
		{
			if(s.size()>=m)
			{
				f[s.front()]=0;
				s.pop();//队头弹出
	     	}
			s.push(x);//队尾插入
			f[x]=1;
			count++;	
		}
	}
	cout<<count; 
}

牛客小白月赛16


其中G题十分简单,但是对精度要求特别高,特此记下PI的高精度表示方式

  • double PI=4.0*atan(1.0)

另外输出格式上三种常见的方法

  1. printf(“%.3lf”, a); //保留a的三位小数,按照第四位四舍五入
  2. (int)a;//将a靠近0取整
  3. ceil(a);floor(a);//向上取整;向下取整;这两个函数都返回double

E、小雨的矩阵

题目描述:

小雨有一个 n×n的矩阵,起点在(1,1),终点在(n,n),只能向下或向右走,且每次只能走 1 步。矩阵上每个点都有一个点权 a i , j a_{i,j} ai,j
求走到终点的路径有多少不同的点权和。

输入描述:

第一行,输入一个正整数 n 。接下来 n+1 行,每行 n 个数,表示 a i , j a_{i,j} ai,j

备注:1<=n<=8 ,0<= a i , j a_{i,j} ai,j<=50

输出描述:

共一行,输出有多少种不同的点权和。

示例1:

输入:
2
1 5
2 4
输出:
2

说明:

(1,1)→(2,1)→(2,2):和为7。(1,1)→(1,2)→(2,2):和为10。

这是一道典型的DFS简单题,直接套模板就能行。

其中有一个关键点用到了STL里的set容器:

set(集合):描述一个控制变长元素序列的对象。包含了经过排序了的数据,这些数据的值(value)必须是唯一的。

所以题中要求不同的点权和,用set存储就十分方便,不用去判断是否唯一。

#include
using namespace std;
long long a[MAXN][MAXN];
int n;
set<int> s;

void dfs(int x,int y,int sum){
    if(x==n && y==n){
        s.insert(sum);	//走到(n,n)则把sum插入集合s
        return;
    }
    if(x+1<=n){
        dfs(x+1,y,sum+a[x+1][y]);//向下走
    }
    if(y+1<=n){
        dfs(x,y+1,sum+a[x][y+1]);//向右走
    }
}
 
int main() {
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j];	//录入矩阵
        }
    }
    dfs(1,1,a[1][1]);	//开始深搜
    cout<<s.size()<<endl;//输出集合s的大小
    return 0;
}

补充:

容器(Container)的概念的出现早于模板(template),它原本是一个计算机科学领域中的一个重要概念,但在这里,它的概念和STL混合在一起了。

下面是在STL中出现的7种容器:

  • vector(向量)——STL中标准而安全的数组。只能在vector 的“前面”增加数据。

  • deque(双端队列double-ended queue)——在功能上和vector相似,但是可以在前后两端向其中添加数据。

  • list(列表)——游标一次只可以移动一步。如果你对链表已经很熟悉,那么STL中的list则是一个双向链表(每个节点有指向前驱和指向后继的两个指针)。

  • set(集合)——包含了经过排序了的数据,这些数据的值(value)必须是唯一的。

  • map(映射)——经过排序了的二元组的集合,map中的每个元素都是由两个值组成,其中的key(键值,一个map中的键值必须是唯一的)是在排序 或搜索时使用,它的值可以在容器中重新获取;而另一个值是该元素关联的数值。比如,除了可以ar[43] = "overripe"这样找到一个数据,map还可以通过ar[“banana”] = "overripe"这样的方法找到一个数据。如果你想获得其中的元素信息,通过输入元素的全名就可以轻松实现。

  • multiset(多重集)——和集合(set)相似,然而其中的值不要求必须是唯一的(即可以有重复)。

  • multimap(多重映射)——和映射(map)相似,然而其中的键值不要求必须是唯一的(即可以有重复)。

你可能感兴趣的:(牛客网,洛谷,算法,STL)