week3-Trie-BFS-DFS-拓扑排序-Dijkstra

文章介绍了Trie树在字符串统计和最大异或对问题中的应用,以及Dijkstra算法在求解最短路问题上的实现,包括堆优化和处理负权边的情况。同时,提到了最小生成树在构建有向无环图中的作用。这些内容涵盖了基础数据结构和算法在解决实际问题中的重要性。
摘要由CSDN通过智能技术生成

Trie树

存储字符串
查询字符串出现了多少次

模板

#include<iostream>
using namespace std;

const int N=100010;

int son[N][26];  //存每个点的所有儿子  N当前节点的下标
int  cnt[N];  //以当前这个点结尾的单词有多少个
int idx; // 当前 用到了哪个下标 ,下标是0的点,既是根节点,又是空节点
char str[N];
void insert(char str[])
{
	int p=0;
	for(int i=0;str[i];i++)
	{
		int u=str[i]-'a';
		if(!son[p][u])  son[p][u]=++idx;
		p=son[p][u];
	}
	cnt[p]++;
 } 
 
 int query(char str[])
 {
 	int p=0;
 	for(int i=0;str[i];i++)
 	{
 		int u=str[i]-'a';
 		if(!son[p][u])   return 0;
 		p=son[p][u];
	 }
	 return cnt[p];
 }
 
 int main()
 {
 	int n;
 	scanf("%d",&n);
 	while(n--)
 	{
 		char op[2]; //通过字符串来读
 		scanf("%s%s",&op,&str);  //%s 自动过滤空格回车
 		if(op[0]=='I')  insert(str);
 		else printf("%d\n",query(str));
	 }
 }

最大异或对

在给定的N个整数A1,A2.。。。An中选出两个进行异或运算,得到的结果最大是多少?
输入格式
第一行输入一个整数N
第二行输入N个整数A~An
输出格式
输出一个整数表示答案
数据范围
1<=N<=1e5
0<=Ai<2e31
输入样例
3
1 2 3
输出样例
3

#include<iostream>
#include<cstring>
using namespace std;
const int N=100010,M=31*N;
int n;
int a[N];
int son[M][2],idx;
void insert(int x)
{
	int p=0;
	for(int i=30;i>=0;i--)
	{
		int u=x>>i&1;
		if(!son[p][u])  son[p][u] =++idx;
		p=son[p][u];
	}
}
int query(int x)
{
	int p=0,res=0;
	for(int i=30;i>=0;i--)
	{
		int u=x>>i&1;
		if(son[p][!u])
		{
			p=son[p][u];
			res=res*2+ !u;
		}
		else
		{
			p=son[p][u];
			res=res*2+u;
		}
	}
	return res;
 } 
int main()
{
	cin>>n;
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	int res=0;
	for(int i=0;i<n;i++)
	{
		insert(a[i]);
		int t=query(a[i]);
		res=max(res,a[i]^t);
	}
	printf("%d\n",res);
	return 0;
} 

Tire字符串统计

最大异或和

BFS

微博转发

全球气候变暖

走迷宫

0为通路
输入
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出
8

#include <iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
const  int N=110;
int n,m;
int g[N][N];
int d[N][N];
PII q[N*N];
int bfs()
{
	int hh=0,tt=0;
	q[0]={0,0};
	memset(d,-1,sizeof d);
	d[0][0]=0;
	int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
	
	while(hh<=tt)
	{
		auto t=q[hh++];
		for(int i=0;i<4;i++)
		{
			int x=t.first+dx[i],y=t.second+dy[i];
			if(x>=0&&x<n&&y>=0&&y<m&&g[x][y]==0&&d[x][y]==-1)
			{
				d[x][y]=d[t.first][t.second]+1;
				q[++tt]={x,y};
			}
		}
	}
	return d[n-1][m-1];
}
int main()
{
	
	cin>>n>>m;
	for(int i=0;i<n;i++)
	  for(int j=0;j<m;j++)
	     cin>>g[i][j];
	cout<<bfs()<<endl;
}

输出路径(倒叙)
4 4
3 4
2 4
2 3
2 2
2 1
2 0
1 0
8

#include <iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
const  int N=110;
int n,m;
int g[N][N];
int d[N][N];
PII q[N*N],Prev[N][N];
int bfs()
{
	int hh=0,tt=0;
	q[0]={0,0};
	memset(d,-1,sizeof d);
	d[0][0]=0;
	int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
	
	while(hh<=tt)
	{
		auto t=q[hh++];
		for(int i=0;i<4;i++)
		{
			int x=t.first+dx[i],y=t.second+dy[i];
			if(x>=0&&x<n&&y>=0&&y<m&&g[x][y]==0&&d[x][y]==-1)
			{
				d[x][y]=d[t.first][t.second]+1;
				Prev[x][y]=t;
				q[++tt]={x,y};
			}
		}
	}
	int x=n-1,y=m-1;
	while(x||y)
	{
		cout<<x<<" "<<y<<endl;
		auto t=Prev[x][y];
		x=t.first,y=t.second;
	}
	return d[n-1][m-1];
}
int main()
{
	
	cin>>n>>m;
	for(int i=0;i<n;i++)
	  for(int j=0;j<m;j++)
	     cin>>g[i][j];
	cout<<bfs()<<endl;
}

八数码

全球变暖

DFS

不同路径数

排列数字

输入
3
输出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

#include <iostream>
#include<algorithm>
using namespace std;
const int N=10;
int path[N];
bool st[N];
int n;
void dfs(int u)
{
	if(u==n)  
	{
		for(int i=0;i<n;i++)   cout<<path[i]<<" ";
		cout<<endl; 
		return ;
	}
	 for(int i=1;i<=n;i++)
	 {
	 	if(!st[i])
	 	{
	 		path[u]=i;
	 		st[i]=true;
	 		dfs(u+1);
	 		st[i]=false;//恢复现场 
		 }
	 }
}
int main()
{
 cin>>n;
 dfs(0);
}

n-皇后问题

输入
4
输出
.Q…
…Q
Q…
…Q.

…Q.
Q…
…Q
.Q…

#include <iostream>
#include<algorithm>
using namespace std;
const int N=20;
char g[N][N];
bool col[N],dg[N],udg[N];
int n;
void dfs(int u)
{
	if(n==u)
	{
		for(int i=0;i<n;i++)  puts(g[i]);
		puts("");
		return ;
	}
	for(int i=0;i<n;i++)
	  if(!col[i]&&!dg[u+i]&&!udg[n-u+i])  //截距b=y-x
	                                     //    b=y+x
	  {
	  	g[u][i]='Q';
	  	col[i]=dg[u+i]=udg[n-u+i]=true;
	  	dfs(u+1);
	  	col[i]=dg[u+i]=udg[n-u+i]=false;
	  	g[u][i]='.';
	  }
}
int main() 
{

 cin>>n;
 for(int i=0;i<n;i++)
   for(int j=0;j<n;j++)
      g[i][j]='.';
      
 dfs(0);
}

小猫爬山

带分数

拓扑排序

构造有向无环图

有向图的拓扑排序

最短路

在这里插入图片描述

Dijkstra

Dijkstra求最短路I

在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=510;
int n,m;
int g[N][N];
int dist[N];
bool st[N];
int dijkstra()
{
	//初始化距离
	memset(dist,0x3f,sizeof dist);   
	dist[1]=0;
	//迭代n次 ,先找最小值 ,当前没有确定最短路长度的所有点中距离最小的 
	for(int i=0;i<n;i++)
	{
		int t=-1;  //还没有确定最短路 
		//遍历所有点 
		for(int j=1;j<=n;j++)
		  if(!st[j]&&(t==-1||dist[t]>dist[j]))
		    t=j;
		    
		st[t]=true;  //把t加到集合里 
		
		for(int j=1;j<=n;j++)
		  dist[j]=min(dist[j],dist[t]+g[t][j]);  //更新1~j的长度 
			 
	}
	if(dist[n]==0x3f3f3f3f)   return -1;   //不存在 ,1和n不连通 
	return dist[n];
}
int main()
{
	cin>>n>>m;
	//初始化邻接矩阵
	memset(g,0x3f,sizeof g);
	
	while(m--)
	{
		int a,b,c;
		cin>>a>>b>>c;
		g[a][b]=min(g[a][b],c);  //a和b之间的边保留长度最短的那条边 
	 } 
	 int t=dijkstra();
	 cout<<t<<endl;
	 
	 return 0;
 } 

Dijkstra求最短路II——堆优化

在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue> 
using namespace std;
typedef pair<int,int> PII;
const int N=100010;
int n,m;
int h[N],e[N],ne[N],w[N];
int dist[N];
bool st[N];
int idx;
void add(int a,int b,int c)
{
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra()
{
	//初始化距离
	memset(dist,0x3f,sizeof dist);   
	dist[1]=0;
	
	priority_queue<PII,vector<PII>,greater<PII>>heap;
	heap.push({0,1});
	while(heap.size())
	{
		auto t=heap.top();
		heap.pop();
		
		int ver=t.second,distance=t.first;
		if(st[ver])  continue;
		
		for(int i=h[ver];i!=-1;i=ne[i])
		{
			int j=e[i];
			if(dist[j]>distance+w[i])
			{
				dist[j]=distance+w[i];
				heap.push({dist[j],j});
			}
		}
	}
	
	if(dist[n]==0x3f3f3f3f)   return -1;   //不存在 ,1和n不连通 
	return dist[n];
}
int main()
{
	cin>>n>>m;
	//初始化邻接表 
	memset(h,-1,sizeof h);
	
	while(m--)
	{
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);  
	 } 
	 int t=dijkstra();
	 cout<<t<<endl;
	 
	 return 0;
 } 

存在负权边——Bellman-Ford

在这里插入图片描述
输出 3

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,k;

const int N=510,M=10010;
int dist[N],backup[N];
struct Edge{
  int a,b,c;
}edges[M];
//不超过k条边
int  bellman_ford()
{
	memset(dist,0x3f,sizeof dist);  
	dist[1]=0;                       //初始化
	
	for(int i=0;i<k;i++)
	{
		memcpy(backup,dist,sizeof dist);
		for(int j=0;j<m;j++)   //遍历所有边
		{
			int a=edges[j].a,b=edges[j].b,c=edges[j].c;
			dist[b]=min(dist[b],backup[a]+c);
		}
	}
	if(dist[n]>0x3f3f3f3f/2)  return -1;
	else return dist[n];
}
int main()
{
	cin>>n>>m>>k;
	for(int i=0;i<m;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		edges[i]={a,b,c};
	}
	int t=bellman_ford();
	if(t==-1)   puts("impossible");
	else cout<<t;
}

多源汇最短路——Floyd算法

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=210;
int dist[N][N],INF=1e9;
int n,m,Q;
void floyd()
{
	for(int k=1;k<=n;k++)
	  for(int i=1;i<=n;i++ )
	    for(int j=1;j<=n;j++)
		   dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]) ;
}
int main()
{
	cin>>n>>m>>Q;
	for(int i=1;i<=n;i++)  
	  for(int j=1;j<=n;j++)
	    if(i==j)  dist[i][j]=0;
	     else dist[i][j]=INF;
	     
	while(m--)
	{
		int a,b,w;
		cin>>a>>b>>w;
		dist[a][b]=min(dist[a][b],w);
	}
	 floyd();
	 while(Q--)
	 {
	 	int a,b;
	 	cin>>a>>b;
	 	if(dist[a][b]>INF/2)  puts("impossible");
	 	else
	 	cout<<dist[a][b];
	 }
}

最短距离

道路与航线

最小生成树

在这里插入图片描述
样例二
5 10
1 2 8
2 2 7
2 1 1
3 4 3
4 4 -10
1 3 -9
5 2 -4
3 1 0
1 4 8
4 4 7
输出
-9

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
const int N=1010,INF=0x3f3f3f3f;
int g[N][N],d[N];
bool st[N];
int prim()
{
	memset(d,0x3f,sizeof d);
	int res=0;
	
	for(int i=0;i<n;i++)   //循环n次 
	{
		int t=-1;
		for(int j=1;j<=n;j++)
		    if(!st[j]&&(t==-1||d[t]>d[j]))
		      t=j;
		      
		if(i&&d[t]==INF)  return INF;
		if(i)  res+=d[t];
		
		for(int j=1;j<=n;j++)  d[j]=min(d[j],g[t][j]);
		st[t]=true;
		
	 } 
	 return res;
}
int main()
{
	cin>>n>>m;
	memset(g,0x3f,sizeof g);
	while(m--)
	{
		int a,b,c;
		cin>>a>>b>>c;
		g[a][b]=g[b][a]=min(g[a][b],c);
	 } 
	 int t=prim();
	 
	 if(t==INF)   puts("impossible");
	 cout<<t<<endl;
}

Kruskal

4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
输出
6

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=100010;
int n,m,p[N];
struct Edge{
	int a,b,w; 
	bool operator<(const Edge &W) const
	{
		return w<W.w;
	}
}edges[N];
int find(int x)
{
	if(x!=p[x])  p[x]=find(p[x]);
	return p[x];
}
int main()
{
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int a,b,w;
		cin>>a>>b>>w;
		edges[i]={a,b,w};
	}
	sort(edges,edges+m);
	
	for(int i=1;i<=n;i++)  p[i]=i;//初始化 
	
	int res=0,cnt=0;
	for(int i=0;i<m;i++)
	{
		int a=edges[i].a,b=edges[i].b,w=edges[i].w;
		
		a=find(a),b=find(b);
		if(a!=b)   //不在一个集合
		{
			p[a]=b;
			res+=w;
			cnt++;
		 } 
	 } 
	 if(cnt<n-1)  puts("impossible");
	 else printf("%d\n",res);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值