3.1总结

T1 B3643 图的存储

基础的邻接矩阵与邻接表问题,只是要注意邻接表要排序

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e3+5;
int n,m;
int G[maxn][maxn];
vector<int>vt[maxn];
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		G[u][v]=G[v][u]=1;
		vt[u].push_back(v);
		vt[v].push_back(u);
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout<<G[i][j]<<' ';
		}
		cout<<endl;
	}
	for(int i=1;i<=n;i++){
		cout<<vt[i].size()<<' ';
		sort(vt[i].begin(),vt[i].end()); 
		for(int v:vt[i]){
			cout<<v<<' ';
		}
		cout<<endl;
	}
	return 0;
}
//haha

T2 P3916 图的遍历

错因:ans数组标记错误,未初始化为-1进行判断

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

点击查看代码
#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(n\log n)$ 错因:没有想到用邻接矩阵判断是否有边

P1692 部落卫队

考虑到n只有100,所以使用邻接矩阵存图判断与一个点相邻的边是否选过了,在做选和不选问题
同时进行剪枝,如果已经选了的加上剩下没选的还没有最大值多,那么后面全选也没有用了

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e3+5;
int n,m;
vector<int>vt[maxn];
int vis[maxn],G[maxn][maxn],ans[maxn],maxi=-1e9;
void dfs(int x,int sum){
	if(x==n+1){//所有点都选过了
		if(sum>maxi){//更多人数
			maxi=sum;
			for(int i=1;i<=n;i++){
				ans[i]=vis[i];//选了的人
			}
		}
		return;
	}
	if(n+sum-x+1<maxi){//剪枝
		return;
	}
	bool flag=0;
	for(int i=1;i<x;i++){//判断是否能选
		if(vis[i]==1&&G[x][i]==1){//不能选
			flag=1;
			break;
		}
	}
	if(flag==0){
		vis[x]=1;//标记
		dfs(x+1,sum+1);//选
		vis[x]=0;//回溯
	}
	dfs(x+1,sum);//不选
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		G[u][v]=G[v][u]=1;//邻接表存图
	}
	dfs(1,0);
	cout<<maxi<<endl;
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<' ';
	}
	return 0;
}
//haha

错因:dfs搜索时细节

T4 P8605 [蓝桥杯 2013 国 AC] 网络寻路

朴素做法就是直接dfs搜四个点,判断即可
但是时间复杂度\(O(n^2)\)
优化:
如下图

四个点的链,可以固定中间标红的边,就可以根据乘法原理求解,同时还有一条相反的路径,答案乘2

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+5;
int n,m;
vector<int>vt[maxn];
int vis[maxn],ans,u[maxn],v[maxn];
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>u[i]>>v[i];//记录边
		vt[v[i]].push_back(u[i]);
		vt[u[i]].push_back(v[i]);//存图
	}
	for(int i=1;i<=m;i++){//枚举中间边
		ans+=1ll*(vt[u[i]].size()-1)*(vt[v[i]].size()-1)*2; //乘法原理
	}
	cout<<ans<<endl;
	return 0;
}
//haha
posted @ 2025-03-02 20:42  KK_SpongeBob  阅读(45)  评论(0)    收藏  举报