首页 > 其他分享 >10.22-10.23图论总结

10.22-10.23图论总结

时间:2022-10-22 22:11:24浏览次数:84  
标签:10.22 ch int 图论 read while 10.23 include getchar

虽然刷的大部分都是水题,但也是花费时间了的。所以还是总结一下吧。

3239:最短路

求\(1\)到\(n\)的最短路。
思路:直接单源最短路模板。

点击查看代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<utility>
using namespace std;
inline int read(){
	int w=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=w*10+ch-'0';
		ch=getchar();
	}
	return w*f;
}
int n,m,s;
vector< pair<int,int> > g[100005];
long long dis[100005];
bool vis[100005];
priority_queue<pair<long long,int> ,vector<pair<long long,int> >,greater< pair<long long,int> > > q;
void dij(){
	for(int i=1;i<=n;i++){
		dis[i]=0x7fffffff;
	}
	dis[s]=0;
	q.push(make_pair(0,s));
	while(!q.empty()){
		int u=q.top().second;
		long long w=q.top().first;
		q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=0;i<g[u].size();i++){
			int v=g[u][i].second;
			int ww=g[u][i].first;
			if(vis[v]) continue;
			if(w+ww<dis[v]){
				dis[v]=w+ww;
				q.push(make_pair(dis[v],v));
			}
		}
	}
}
int main(){
	n=read(),m=read(),s=1;
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),w=read();
		g[u].push_back(make_pair(w,v));
	}
	dij();
	cout<<dis[n];
	return 0;
}

3240: 小P的Civilization

给定一棵树,操作:路径节点权值加1,求路径上节点权值的最大值。
思路:差分,倍增求路径上节点权值的最大值。一些细节需要注意。

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
inline int read(){
	int w=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=w*10+ch-'0';
		ch=getchar();
	}
	return w*f;
}
int n,m,q,f[500005][20],t,d[500005],dp[500005],maxx[500005][20];
vector<int> g[500005];
void dfs(int x,int fa){
	d[x]=d[fa]+1;
	for(int i=0;i<g[x].size();i++){
		int v=g[x][i];
		if(v==fa) continue;
		f[v][0]=x;
		for(int j=1;j<=t;j++) f[v][j]=f[f[v][j-1]][j-1];
		dfs(v,x);
	} 
}
int lca(int u,int v){
	if(d[u]<d[v]) swap(u,v);
	for(int i=t;i>=0;i--){
		if(d[f[u][i]]>=d[v]) u=f[u][i];
	}
	if(u==v) return u;
	for(int i=t;i>=0;i--){
		if(f[u][i]!=f[v][i]){
			u=f[u][i];
			v=f[v][i];
		}
	}
	return f[u][0];
}
void dfs1(int x,int fa){
	for(int i=0;i<g[x].size();i++){
		int v=g[x][i];
		if(v==fa) continue;	
		dfs1(v,x);
		dp[x]+=dp[v];
	} 
}
void dfs2(int x,int fa){
	for(int i=0;i<g[x].size();i++){
		int v=g[x][i];
		if(v==fa) continue;
		maxx[v][0]=dp[x];
		for(int j=1;j<=t;j++) maxx[v][j]=max(maxx[v][j-1],maxx[f[v][j-1]][j-1]); 
		dfs2(v,x);
	} 
}
int ask_maxx(int u,int v){
	if(d[u]<d[v]) swap(u,v);
	int ans=max(dp[u],dp[v]);
	for(int i=t;i>=0;i--){
		if(d[f[u][i]]>=d[v]){
			ans=max(maxx[u][i],ans);
			u=f[u][i];
		}
	}
	if(u==v) return ans;
	for(int i=t;i>=0;i--){
		if(f[u][i]!=f[v][i]){
			ans=max(ans,max(maxx[u][i],maxx[v][i]));
			u=f[u][i],v=f[v][i];
		} 
	}
	ans=max(ans,maxx[u][0]); 
	return ans;
}
int main(){
    n=read(),m=read(),q=read();
    t=log(n)/log(2)+1;
	for(int i=2;i<=n;i++){
		int u=read();
		g[u].push_back(i);
		g[i].push_back(u);
	} 
	dfs(1,0);
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		int lac=lca(u,v);
		dp[u]+=1,dp[v]+=1,dp[lac]-=1,dp[f[lac][0]]-=1;
	}
	dfs1(1,0);
	dfs2(1,0);
	for(int i=1;i<=q;i++){
		int u=read(),v=read();
		cout<<ask_maxx(u,v)<<"\n";
	}
	return 0;
}

3242: 聚会

给定一棵树,多次查找距离三个点总距离最短的节点,并输出总距离。
思路:两两求LCA,会出现重复的LCA,取不重复的那个LCA,即为目标节点。

点击查看代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
inline int read(){
	int w=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=w*10+ch-'0';
		ch=getchar();
	}
	return w*f;
}
int n,m,f[500005][20],d[500005],t;
vector<int> g[500005];
queue<int> q;
void bfs(){
	q.push(1);
	d[1]=1;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=0;i<g[u].size();i++){
			int v=g[u][i];
			if(d[v]) continue;
			d[v]=d[u]+1;
			f[v][0]=u;
			for(int j=1;j<=t;j++) f[v][j]=f[f[v][j-1]][j-1];
			q.push(v);
		}
	}
}
int lca(int u,int v){
	if(d[u]<d[v]) swap(u,v);
	for(int i=t;i>=0;i--){
		if(d[f[u][i]]>=d[v]) u=f[u][i];
	}
	if(u==v) return u;
	for(int i=t;i>=0;i--){
		if(f[u][i]!=f[v][i]){
			u=f[u][i];
			v=f[v][i];
		}
	}
	return f[u][0];
}
int main(){
	n=read(),m=read();
	t=log(n)/log(2)+1;
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		g[u].push_back(v);
		g[v].push_back(u);
	}
	bfs();
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),k=read();
		int root1=lca(u,v);
		int root2=lca(v,k);
		int root3=lca(u,k);
		int p;
		if(root1==root2) p=root3;
		if(root1==root3) p=root2;
		if(root2==root3) p=root1;
		int ans=d[u]+d[v]+d[k]-d[root1]-d[root2]-d[root3];
		printf("%d %d\n",p,ans);
	}
	return 0;
}

3243: 邮递员送信

求1到其他所有节点并返回1号的总距离。
思路:正向,反向跑最短路即可。

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
inline int read(){
	int w=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=w*10+ch-'0';
		ch=getchar();
	}
	return w*f;
}
int n,m;
int dis[1005];
bool inq[1005];
long long ans;
vector<pair<int,int> > g[1005],g1[1005]; 
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
void dij(){
	memset(inq,0,sizeof(inq));
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	q.push(make_pair(0,1));
	while(!q.empty()){
		int u=q.top().second;
		int w=q.top().first;
		q.pop();
		inq[1]=1;
		for(int i=0;i<g[u].size();i++){
			int v=g[u][i].second;
			int w=g[u][i].first;
			if(inq[v]) continue; 
			if(dis[v]>w+dis[u]){
				dis[v]=dis[u]+w;
				q.push(make_pair(dis[v],v));
			}
		} 
	}
}
void dij1(){
    memset(inq,0,sizeof(inq));
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	q.push(make_pair(0,1));
	while(!q.empty()){
		int u=q.top().second;
		int w=q.top().first;
		q.pop();
		inq[u]=1;
		for(int i=0;i<g1[u].size();i++){
			int v=g1[u][i].second;
			int w=g1[u][i].first;
			if(inq[v]) continue; 
			if(dis[v]>w+dis[u]){
				dis[v]=dis[u]+w;
				q.push(make_pair(dis[v],v));
			}
		} 
	}
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
    	int u=read(),v=read(),w=read();
    	g[u].push_back(make_pair(w,v));
    	g1[v].push_back(make_pair(w,u));
	}
	dij();
	for(int i=2;i<=n;i++) ans+=dis[i];
	dij1();
	for(int i=2;i<=n;i++) ans+=dis[i];
	cout<<ans;
	return 0;
}

3244: 奶牛野餐

给一图,有向边,有若干标记点,求所有标记点都可以到达的节点的个数。
思路:依次从标记点出发,将能走到的节点的到达次数+1,最后扫描,到达次数=标记点的数量的即目标点,统计答案。

点击查看代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
inline int read(){
	int w=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=w*10+ch-'0';
		ch=getchar();
	}
	return w*f;
}
int k,n,m,c[105],s[1005],ans;
vector<int> g[1005];
bool vis[1005],mark[1005];
void bfs(int x){
	queue<int> q;
	q.push(x);
	vis[x]=1;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=0;i<g[u].size();i++){
			int v=g[u][i];
			if(mark[v]) s[v]++;
			if(!vis[v]){
				vis[v]=1;
				s[v]++;
				q.push(v);
			}
		} 
	} 
}
int main(){
    k=read(),n=read(),m=read();
    for(int i=1;i<=k;i++) c[i]=read(),s[c[i]]++;	
    for(int i=1;i<=m;i++){
    	int u=read(),v=read();
    	g[u].push_back(v); 
	}
	for(int i=1;i<=k;i++){
		memset(vis,0,sizeof(vis));
		bfs(c[i]);		
	}
	for(int i=1;i<=n;i++){
		if(s[i]==k) ans++; 
	}
	cout<<ans;
	return 0;
}

3245: 最近公共祖先

LCA模板。

点击查看代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
inline int read(){
	int w=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=w*10+ch-'0';
		ch=getchar();
	}
	return w*f;
}
int n,m,s,t,f[500005][20],d[500005]; 
vector<int> g[500005];
void dfs(int x,int fa){
	d[x]=d[fa]+1;
	for(int i=0;i<g[x].size();i++){
		int v=g[x][i];
		if(v==fa) continue;
		f[v][0]=x;
		for(int j=1;j<=t;j++) f[v][j]=f[f[v][j-1]][j-1];
		dfs(v,x);
	}
}
int lca(int u,int v){
	if(d[u]<d[v]) swap(u,v);
	for(int j=t;j>=0;j--){
		if(d[f[u][j]]>=d[v]) u=f[u][j];
	}
	if(u==v) return u;
	for(int j=t;j>=0;j--){
		if(f[u][j]!=f[v][j]){
			u=f[u][j];
			v=f[v][j];
		}
	}
	return f[u][0];
}
int main(){
    n=read(),m=read();
	t=log(n)/log(2)+1;
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1,0);
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		cout<<lca(u,v)<<"\n";
	}
	return 0;
}

3246: 最小生成树

最小生成树模板。

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
	int w=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=w*10+ch-'0';
		ch=getchar();
	}
	return w*f;
}
int n,m,tot,f[200005];
long long ans;
struct edge{
	int u;
	int v;
	int w;
}e[500005];
bool cmp(edge a,edge b){
	return a.w<b.w;
}
int get(int x){
	if(f[x]==x) return x;
	return f[x]=get(f[x]); 
}
void kru(){
	sort(e+1,e+1+m,cmp);
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=m;i++){
		int u=e[i].u,v=e[i].v,w=e[i].w;
		if(get(u)==get(v)) continue;
		f[get(u)]=get(v);
		tot++;
		ans+=w;
		if(tot==n-1) break;
	}
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		e[i].u=read();
		e[i].v=read();
		e[i].w=read(); 
	}
	kru();
	cout<<ans;
	return 0;
}

3247: 奶牛比赛

给定若干节点的关系,求能确定排名的奶牛的个数。
思路:一个点的排名可以确定,当且仅当它的上面节点数+它的下面节点数==n-1。建正反图对每个点依次统计。

点击查看代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
inline int read(){
	int w=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		w=w*10+ch-'0';
		ch=getchar();
	}
	return w*f;
}
int n,m,ans,sum_win,sum_lose;
bool vis[105];
vector<int> g[105],g1[105];
void dfs_win(int x){
	vis[x]=1;
	sum_win++;
	for(int i=0;i<g1[x].size();i++){
		int v=g1[x][i];
		if(vis[v]) continue;
		dfs_win(v);
	}
} 
void dfs_lose(int x){
	vis[x]=1;
	sum_lose++;
	for(int i=0;i<g[x].size();i++){
		int v=g[x][i];
		if(vis[v]) continue;
		dfs_lose(v);
	} 
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
    	int u=read(),v=read();
    	g[u].push_back(v);
    	g1[v].push_back(u);
	}
	for(int i=1;i<=n;i++){
		sum_win=0,sum_lose=0;
		memset(vis,0,sizeof(vis));
		dfs_win(i);
		memset(vis,0,sizeof(vis));
		dfs_lose(i);
		if(sum_win+sum_lose==n+1) ans++;
	}
	cout<<ans;
	return 0;
}

3248: 灌水

有\(n\)块牧草,可以在当地花费\(wi\)挖一口井,也可一花费一定的钱连向有井的牧草。求使每块牧草都浇上水的最小代价。
思路:建立一个超级大井,将在当地挖井当作连向超级大井。然后最小生成树模板。

点击查看代码 ``` #include #include #include using namespace std; inline int read(){ int w=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ w=w*10+ch-'0'; ch=getchar(); } return w*f; } int n,val[305],tot,f[305],cnt,ans; struct edge{ int u; int v; int w; }e[100005]; bool cmp(edge a,edge b){ return a.w<b.w; }="" int="" get(int="" x){="" if(f[x]="=x)" return="" x;="" f[x]="get(f[x]);" void="" kru(){="" for(int="" i="0;i<=n;i++)" f[i]="i;" sort(e+1,e+1+tot,cmp);="" u="get(e[i].u),v=get(e[i].v),w=e[i].w;" if(u="=v)" continue;="" f[u]="v;" cnt++;="" ans+="w;" if(cnt="=n)" break;="" main(){="" n="read();" val[i]="read();" j="1;j<=n;j++){" w="read();" if(i="=j)" e[++tot].u="i,e[tot].v=j,e[tot].w=w;" e[tot].v="i;" e[tot].w="val[i];" kru();="" cout<<ans;="" 0;="" ```="" <="" details="">

标签:10.22,ch,int,图论,read,while,10.23,include,getchar
From: https://www.cnblogs.com/Jue-Qing/p/16817449.html

相关文章