2.22总结

P5318 【深基18.例3】查找文献

考查图上深搜与图上广搜
深搜:
采用邻接表存图
如果u->v有一条边,那么在遍历了u之后遍历v;
同时每个点只能走一次,所以使用vis进行标记,没有被标记过才能继续递归

void dfs(int x){
	cout<<x<<' ';
	for(int v:vt[x]){
		if(vis[v]==0){
			vis[v]=1;
			dfs(v);
		}
	}
}

广搜:
同理,只是将递归改为入队即可

void bfs(int x){
	queue<int>q;
	q.push(x);
	while(!q.empty()){
		int x=q.front();
		q.pop();
		if(vis[x]==1){
			continue;
		}
		vis[x]=1;
		cout<<x<<' ';
		for(int v:vt[x]){
			q.push(v);
		}
	}
}

合并起来:

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,m;
vector<int>vt[maxn];
bool vis[maxn];
void dfs(int x){
	vis[x]=1;
	cout<<x<<' ';
	for(int v:vt[x]){
		if(vis[v]==0){
			dfs(v);
		}
	}
}
void bfs(int x){
	queue<int>q;
	q.push(x);
	while(!q.empty()){
		int x=q.front();
		q.pop();
		if(vis[x]==1){
			continue;
		}
		vis[x]=1;
		cout<<x<<' ';
		for(int v:vt[x]){
			q.push(v);
		}
	}
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		vt[u].push_back(v);
	}
	for(int i=1;i<=n;i++){
		sort(vt[i].begin(),vt[i].end());
	}
	dfs(1);
	cout<<endl;
	memset(vis,0,sizeof(vis));
	bfs(1);
	return 0;
}

P3916 图的遍历

朴素做法:
对于每个点,跑一遍深搜,不断更新最大值
时间复杂度O(n2logn)
优化做法:
考虑逆思维,可以从每个最大的点去找能到达的点,反向建图,细节见代码

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,m;
vector<int>vt[maxn];
bool vis[maxn];
int ans[maxn];
void dfs(int x,int root){	
	vis[x]=1;
	if(ans[x]!=-1){
		return;
	}
	ans[x]=root;
	for(int v:vt[x]){
		if(vis[v]==0){
			dfs(v,root);
		}
	}
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		vt[v].push_back(u);//反向建图
	}
	memset(ans,-1,sizeof(ans));
	for(int i=n;i>=1;i--){//从最大的开始
		dfs(i,i);//遍历可到达的点
	}
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<' ';
	}
	return 0;
}


时间复杂度O(nlogn)

P2853 [USACO06DEC] Cow Picnic S

使用一个桶记录每个点能被多少头奶牛经过,如果数量为k则答案加一

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,m,k;
vector<int>vt[maxn];
bool vis[maxn];
int cow[maxn],sz[maxn];
void dfs(int x){
	sz[x]++;
	vis[x]=1;
	for(int v:vt[x]){
		if(vis[v]==0){
			dfs(v);
		}
	}
}
signed main(){
	cin>>k>>n>>m;
	for(int i=1;i<=k;i++){
		cin>>cow[i];
	}
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		vt[u].push_back(v);
	}
	for(int i=1;i<=n;i++){//每一头奶牛
		dfs(cow[i]);//dfs搜索+标记
		memset(vis,0,sizeof(vis));//清空
	}
	int sum=0;
	for(int i=1;i<=n;i++){
		if(sz[i]==k){
			sum++;
		}
	}
	cout<<sum;
	return 0;
}

P7370 [COCI 2018/2019 #4] Wand

建反图
如果B打败了A,那么魔杖从B到A
如果从1开始,能到达i,则因为可以随意调整顺序,所以i一定可以拿到魔杖
同时从1开始,不要标记1,因为如果不存在一个包含1的环,则1不能拿到魔杖
特殊情况:没有人能打败1,即vt[1]==0,此时魔杖一定在1手上

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,m;
vector<int>vt[maxn];
bool vis[maxn];
int ans[maxn];
void dfs(int x){	
	
	for(int v:vt[x]){
		if(vis[v]==0){vis[v]=1;
			dfs(v);
			
		}
	}
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		vt[v].push_back(u);
	}
	dfs(1);
	if(vt[1].size()==0){
		vis[1]=1;
	}
	for(int i=1;i<=n;i++){
		cout<<vis[i];
	}
	return 0;
}
posted @   KK_SpongeBob  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
点击右上角即可分享
微信分享提示