题解:CF164A Variable, or There and Back Again
CF164A 题解
题目传送门
蒟蒻的第一篇题解,求过!!!
题目大意
说实话,其实下面两位大佬写的题目大意已经够详细了。不过要注意的是,可能存在多个标记为
暴力做法
思路
暴力的算法应该不难想出来,只需要遍历所有标记为
代码
这个代码还可以优化。
#include<bits/stdc++.h>
using namespace std;
int n,m,f[100010],r[100010],maxn=0,ansr[100010];
vector<int> ve[100010];
void get_ans(){//标记
for(int i=1;i<=n;i++){
ansr[i]=max(r[i],ansr[i]);
}
}
void dfs(int d,int maxl){//深度优先搜索
if(r[d]==1) return; //已经被遍历过了
r[d]=1;//标记走过
if(f[d]==2){
get_ans();
}
for(int i=0;i<ve[d].size();i++){
dfs(ve[d][i],maxl+1);
}
r[d]=0;//回溯
}
void add(int x,int y){//存边,注意是有向图
ve[x].push_back(y);
//ve[y].push_back(x);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&f[i]);
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++){
if(f[i]==1){
dfs(i,1);
}
}
for(int i=1;i<=n;i++){
printf("%d\n",ansr[i]);
}
return 0;
}
满分做法
思路
其实我们只需要换一个思路。可以从所有标记为
这里也有一个注意点,就是应该注意在第二次遍历的时候,碰到标记为 因为这个我 WA 了两次)。
代码
代码我是使用 DFS 实现的,楼下两个大佬都是 BFS。
我才不会告诉你我是因为 BFS 不会才用 DFS 的。
#include<bits/stdc++.h>
using namespace std;
int n,m,f[100010],r[100010],maxn=0,k1[100010],k2[100010];
vector<int> ve1[100010],ve2[100010];
void add(int x,int y){
ve1[x].push_back(y);
ve2[y].push_back(x);
}
void dfs1(int d){//标记为1的遍历
if(k1[d]) return;
k1[d]=1;
for(int i=0;i<ve1[d].size();i++){
dfs1(ve1[d][i]);
}
}
void dfs2(int d){//标记为2的遍历
if(k2[d]) return;
k2[d]=1;
if(f[d]==1) return;//遇到标记为1的就应该标记后就停止遍历
for(int i=0;i<ve2[d].size();i++){
dfs2(ve2[d][i]);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&f[i]);
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++){
if(f[i]==1){//遇到标记为1的
dfs1(i);
}else if(f[i]==2){//遇到标记为2的
dfs2(i);
}
}
for(int i=1;i<=n;i++){
if(k1[i]+k2[i]==2) printf("1\n");
else printf("0\n");
}
return 0;
}