2020天梯决赛(L3-1 那就别担心了)

第一题

L3-1 那就别担心了

问题分析

题目意思就是,给定一张有向无环图,让你判断从 s 到 t 有多少条路径数。
还要判断一下是否”逻辑自洽“,即判断终点(出度为0的点)是否只有 t

算法1:dfs暴力跑图。能拿大部分的分,但是TLE

算法2:dfs+剪枝。 O(n)

设num[u]为u能到终点的条数

代码如下

#include<bits/stdc++.h>
using namespace std;
const int N=600;
struct ppp {
    
    
	int u,v,next;
} e[N*N];
int vex[N],k,vis[N],s,t,num[N],out[N],key=0;

void add(int u,int v) {
    
    
	k++;
	e[k].u=u;
	e[k].v=v;
	e[k].next=vex[u];
	vex[u]=k;
}
void dfs(int u) {
    
    //计算u能到t的条数 
	vis[u]=1;
	if(out[u]==0&&u!=t) {
    
    //最终命题不是t,不逻辑自洽 
		key=1;
		return;
	}
	if(u==t) {
    
    //到终点了,计数 
		num[u]=1;
		return;
	}
	for(int i=vex[u]; i; i=e[i].next) {
    
    
		int v=e[i].v;
		if(vis[v]) {
    
    //u也能到v,那么u能到t的条数加上v能到t的条数 
			num[u]+=num[v];
			continue;
		}
		dfs(v);
		num[u]+=num[v];
	}
}
int main() {
    
    
	int n,m,u,v;
	cin>>n>>m;
	for(int i=1; i<=m; i++) {
    
    
		cin>>u>>v;
		add(u,v);
		out[u]++;//为了判断逻辑自洽
	}
	cin>>s>>t;
	dfs(s);
	cout<<num[s]<<" ";

	if(key==0)cout<<"Yes";
	else cout<<"No";
	return 0;
}

算法3:拓扑排序跑图。保证了每个点只经过一次,O(n),轻松过

为了避免有其他出度为0的点导致从s出发不能跑拓扑序,我们先从其他出度为0的点先跑一遍,再从s出发跑拓扑序

代码如下(有两个点没过,不知道是什么细节没考虑到)

#include<bits/stdc++.h>
using namespace std;
const int N=600;
struct ppp {
    
    
	int u,v,next;
} e[N*N];
int vex[N],k,vis[N],s,t,in[N],out[N],key=0,lu[N];
int n;

queue<int>q;

void add(int u,int v) {
    
    
	k++;
	e[k].u=u;
	e[k].v=v;
	e[k].next=vex[u];
	vex[u]=k;
}
void topoOrder() {
    
    //跑拓扑序
	for(int i=1; i<=n; i++)if(in[i]==0&&i!=s)q.push(i);
	while(!q.empty()) {
    
    
		int u=q.front();
		for(int i=vex[u]; i; i=e[i].next) {
    
    
			int v=e[i].v;
			in[v]--;
			if(in[v]==0)q.push(v);
		}
		q.pop();
	}

	q.push(s);
	lu[s]=1;//起点路径数初始化为1
	while(!q.empty()) {
    
    
		int u=q.front();
		q.pop();
		if(u!=t&&out[u]==0)key=1;
		for(int i=vex[u]; i; i=e[i].next) {
    
    
			int v=e[i].v;
			lu[v]+=lu[u];//能到u的路径也能到v
			in[v]--;
			if(in[v]==0)q.push(v);
		}
	}
	cout<<lu[t];
	if(key==0)cout<<" Yes";
	else cout<<" No";
}
int main() {
    
    
	int n,m,u,v;
	cin>>n>>m;
	for(int i=1; i<=m; i++) {
    
    
		cin>>u>>v;
		add(u,v);
		in[v]++;//预处理入读,为了拓扑序
		out[u]++;//预处理出度,为了判断逻辑自洽
	}
	cin>>s>>t;
	topoOrder();

	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43602607/article/details/114436822