第一题
问题分析
题目意思就是,给定一张有向无环图,让你判断从 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;
}