牛牛想知道,他是否能从
号格子出发回到
号格子。
若能回到 号格子则返回Yes,否则返回No。
若能回到 号格子则返回Yes,否则返回No。
[4, 4],[(1,2), (2, 3), (3,4),(4,1)]
"Yes"
m对 u, v 互不相同
dfs只要从1节点开始查找判断,每走过一个点标记一下,并且不能回头踩上一个节点即可。
因为我们只需要判断1节点出来后能不能回去,无论怎么走,之所以用深度是因为1节点每条路的连通图先便利完判断是否回到1,这样时间最多就是遍历所有的点O(n)
代码:
/**
* struct Point {
* int x;
* int y;
* };
*/
class Solution {
public:
/**
* 能回到1号点返回 Yes,否则返回 No
* @param param int整型vector param[0] 为 n,param[1] 为 m
* @param edge Point类vector Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
vector<int> ve[100005];
bool vis[100005];
bool dfs(int u, int fa) {
for (auto &i : ve[u]) {
if (i == fa) continue;
if (i == 1) return true;
if (vis[i]) continue;
vis[i] = true;
if (dfs(i, u)) return true;
}
return false;
}
string solve(vector<int>& param, vector<Point>& edge) {
// write code here
for (auto &i : edge) {
ve[i.x].push_back(i.y);
ve[i.y].push_back(i.x);
}
memset(vis, 0, sizeof(vis));
if (dfs(1, 1)) return "Yes";
else return "No";
}
};
public class Solution {
//并查集
private int[] uninonFindSet;
//连接1号节点的节点集
private HashSet<Integer> nodeToOne;
//连接1号节点的连通子图(用并查集中的头节点代表一个连通子图)
private HashSet<Integer> linkToOne;
public String solve(int[] param, Point[] edge) {
//排除特例
if (param[1] == 0)
return "NO";
//构建并查集
createUnionFindSet(param[0], edge);
//判断1号节点是否存在回路,返回结果
return isCircuit();
}
private String isCircuit() {
//根据1号节点的连接点,将1号节点与连通子图关联起来
for (Integer node : nodeToOne) {
Integer head = findHead(node);
//如果连通子图的头节点已经连接了1号节点,则存在回路;
if (linkToOne.contains(head)) {
return "Yes";
} else {
//否则,在集合中添加连通子图的头节点;
linkToOne.add(head);
}
}
return "No";
}
private void initialize(int n) {
//数组初始化时,默认每个节点的boss为0
uninonFindSet = new int[n + 5];
//连接1的节点默认估计值为 128 个
nodeToOne = new HashSet<Integer>(128);
//连接1的boss节点默认估计值为 128 个
linkToOne = new HashSet<Integer>(128);
}
private void createUnionFindSet(int n, Point[] edge) {
initialize(n);
for (Point p : edge) {
//只记录1号节点的连接点,不参与构建并查集
if (p.x == 1 || p.y == 1) {
//注意:本程序没有考虑 (1,x),(x,1) 这种连接关系
int node = p.x != 1 ? p.x : p.y;
nodeToOne.add(node);
} else if (!isSameHead(p.x, p.y)) {
unionSet(p.x, p.y);
}
}
}
private boolean isSameHead(int x, int y) {
return findHead(x) == findHead(y);
}
private void unionSet(int u, int v) {
int uHead = findHead(u), vHead = findHead(v);
uninonFindSet[uHead] = vHead;
}
//非递归版本:防止测试数据暴栈
private int findHead(int node) {
int head = node;
while (uninonFindSet[head] != 0) {
//真正的头节点 = 头节点的头节点
head = uninonFindSet[head];
}
//并查集扁平化
int curNode = node, nextNode = uninonFindSet[node];
while (nextNode != 0) {
uninonFindSet[curNode] = head;
curNode = nextNode;
nextNode = uninonFindSet[nextNode];
}
return head;
}
} 其它解题思路:广度优先搜索(BFS)#define pb push_back
const int maxn = 1e5+5;
class Solution {
public:
vector<int>G[maxn];
bool vis[maxn];
string solve(vector<int>& param, vector<Point>& edge) {
int n = param[0], m = param[1];
for(int i = 0; i < m; i++) {
int u = edge[i].x, v = edge[i].y;
G[u].pb(v);
G[v].pb(u);
}
if(dfs(1, 1)) return "Yes";
else return "No";
}
bool dfs(int u, int f) {
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(v == f) continue;
if(vis[v]) continue;
vis[v] = true;
if(v == 1 || dfs(v, u)) return true;
}
return false;
}
}; 标记边: #define pb push_back
const int maxn = 1e5+5;
struct Edge{
int id, to;
Edge(int a, int b) {
to = a, id = b;
}
};
class Solution {
public:
vector<Edge>G[maxn];
bool vis[maxn];
string solve(vector<int>& param, vector<Point>& edge) {
int n = param[0], m = param[1];
for(int i = 0; i < m; i++) {
int u = edge[i].x, v = edge[i].y;
G[u].pb(Edge(v, i));
G[v].pb(Edge(u, i));
}
if(dfs(1)) return "Yes";
else return "No";
}
bool dfs(int u) {
for(int i = 0; i < G[u].size(); i++) {
Edge e = G[u][i];
if(vis[e.id]) continue;
vis[e.id] = true;
if(e.to == 1 || dfs(e.to)) return true;
}
return false;
}
}; /**
* struct Point {
* int x;
* int y;
* };
*/
class Solution {
public:
/**
* 能回到1号点返回 Yes,否则返回 No
* @param param int整型vector param[0] 为 n,param[1] 为 m
* @param edge Point类vector Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
vector<int> G[100003];
bool vis[100003];
bool DFS(int s, int pre){
for(int i=0;i<G[s].size();i++){
if(G[s][i] == pre)
continue;
if(G[s][i]==1)
return true;
if(!vis[G[s][i]]){
vis[G[s][i]] = true;
if(DFS(G[s][i], s))
return true;
}
}
return false;
}
string solve(vector<int>& param, vector<Point>& edge) {
for(int i=0;i<edge.size();i++){
G[edge[i].x].push_back(edge[i].y);
G[edge[i].y].push_back(edge[i].x);
}
if(DFS(1, 1))
return "Yes";
else
return "No";
}
}; string solve(vector<int>& param, vector<Point>& edge) {
int n = param[0];
int m = param[1];
vector<vector<int>> graph(n+1);
for(int i=0;i<m;i++){
int x = edge[i].x;
int y = edge[i].y;
graph[x].push_back(y);
graph[y].push_back(x);
}
//思路,BFS,按照和1号直接相连的点对结点进行标记
//如果遍历的时候发现两个标记不同的点相遇了,说明存在环路
vector<int> visited(n+1,-1);
visited[1] = 0;
queue<int> q;
q.push(1);
while(q.size() > 0){
int currentPoint = q.front();
q.pop();
for(int i=0;i<graph[currentPoint].size();i++){
int nextPoint = graph[currentPoint][i];
if(visited[nextPoint] == -1){
q.push(nextPoint);
if(currentPoint == 1){ //对点进行标记
visited[nextPoint] = i + 1;
}else{
visited[nextPoint] = visited[currentPoint];
}
}else{
if(visited[nextPoint] != visited[currentPoint] && nextPoint != 1){ //不同的点相遇了
return "Yes";
}
}
}
}
return "No";
} import java.util.*;
/*
* public class Point {
* int x;
* int y;
* public Point(int x, int y) {
* this.x = x;
* this.y = y;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 能回到1号点返回 Yes,否则返回 No
* @param param int整型一维数组 param[0] 为 n,param[1] 为 m
* @param edge Point类一维数组 Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
public boolean flag = false;
public String solve (int[] param, Point[] edge) {
ArrayList[] arrayLists = new ArrayList[param[0]+1];
for(int i = 0 ;i<=param[0];i++){
arrayLists[i] = new ArrayList();
}
for(int i = 0 ;i<edge.length;i++){
arrayLists[edge[i].x].add(new SelfEdge(edge[i].y,false));
arrayLists[edge[i].y].add(new SelfEdge(edge[i].x,false));
}
if(solve1(arrayLists,-1,1))
return "Yes";
else
return "No";
}
public boolean solve1(ArrayList[] arrayLists,int st,int des){
for(Object selfEdge:arrayLists[des]){
SelfEdge tem = (SelfEdge) selfEdge;
if(tem.isVisited)
continue;
if(tem.des == 1){
flag=true;
return true;
}else{
if(flag)
return true;
else{
change(arrayLists,des,tem.des);
solve1(arrayLists,des,tem.des);
change1(arrayLists,des,tem.des);
if(flag)
return true;
}
}
}
return false;
}
public void change(ArrayList[] arrayLists,int st,int des){
for(int i =0 ;i<arrayLists[st].size();i++){
SelfEdge selfEdge = (SelfEdge) arrayLists[st].get(i);
if(selfEdge.des == des){
selfEdge.isVisited = true;
arrayLists[st].set(i,selfEdge);
break;
}
}
for(int i = 0 ;i<arrayLists[des].size();i++){
SelfEdge selfEdge = (SelfEdge) arrayLists[des].get(i);
if(selfEdge.des == st){
selfEdge.isVisited = true;
arrayLists[des].set(i,selfEdge);
break;
}
}
}
public void change1(ArrayList[] arrayLists,int st,int des){
for(int i =0 ;i<arrayLists[st].size();i++){
SelfEdge selfEdge = (SelfEdge) arrayLists[st].get(i);
if(selfEdge.des == des){
selfEdge.isVisited = false;
arrayLists[st].set(i,selfEdge);
break;
}
}
for(int i = 0 ;i<arrayLists[des].size();i++){
SelfEdge selfEdge = (SelfEdge) arrayLists[des].get(i);
if(selfEdge.des == st){
selfEdge.isVisited = false;
arrayLists[des].set(i,selfEdge);
break;
}
}
}
}
class SelfEdge{
int des;
boolean isVisited;
public SelfEdge(int des,boolean isVisited){
this.des = des;
this.isVisited = isVisited;
}
} 构造图进行dfs即可。写得太烂了。。
import java.util.*;
/*
* public class Point {
* int x;
* int y;
* }
*/
public class Solution {
/**
* 能回到1号点返回 Yes,否则返回 No
* @param param int整型一维数组 param[0] 为 n,param[1] 为 m
* @param edge Point类一维数组 Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
public String solve (int[] param, Point[] edge) {
// write code here
if(param[1]>100000 || param[0]>100000){
return "No";
}else{
int num = 0;
for(int i = 0;i<edge.length;i++){
if(edge[i].x ==1 || edge[i].y==1){
num++;
}
}
if(num < 2){
return "No";
}
}
//上面是判断两种不符合题意的情况
List<Integer> list = new ArrayList<>();
for(int i=0;i<edge.length;i++){
if(edge[i].x==1){
list.add(i);
}
}//找出所有1能通向的所有y
if(findAll(list,edge)){
return "Yes";
}
return "No";
}
public boolean findAll(List<Integer> list,Point[] edge){
List<Integer> list2 = new ArrayList<>();//用于递归的list
for(int i = 0;i<list.size();i++){
for(int j = 0;j<edge.length;j++){//对每一个可以通向的节点,进行判断
if(edge[j].y == 1){
return true;//通向1,为true
}
if(edge[j].x == edge[list.get(i)].y){
list2.add(j);//通向的不为1,存入list
}
}
}
if(0==list2.size()){//若没有可以通向的节点,返回false
return false;
}
if(findAll(list2,edge)){//递归进入下一个节点
return true;//当递归到最后一个节点时,为true,则会一路返回到顶层
}
return false;//否则返回false到顶层
}
public List<Integer> find(Point[] edge,int n){//查找当前y能通向的所有x
int i;
List<Integer> list = new ArrayList<>();
for(i = 1;i<edge.length;i++){
if(n == edge[i].x){
list.add(i);
}
}
return list;
}
} /**
* struct Point {
* int x;
* int y;
* };
*/
class Solution {
public:
/**
* 能回到1号点返回 Yes,否则返回 No
* @param param int整型vector param[0] 为 n,param[1] 为 m
* @param edge Point类vector Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
int find_parent(vector<int>& uf, int node) {
int temp = node;
while (uf[temp] != temp) {
temp = uf[temp];
}
uf[node] = temp;
return temp;
}
void union_node(vector<int>& uf, vector<int>& rank, int a, int b) {
int pa = find_parent(uf, a);
int pb = find_parent(uf, b);
if (pa == pb) return;
if (rank[a]> rank[b]) swap(pa, pb);
uf[pa] = pb;
if (rank[pa] == rank[pb]) ++rank[pb];
}
string solve(vector<int>& param, vector<Point>& edge) {
// write code here
int n = param[0];
int m = param[1];
vector<int> uf(n+1, 0);
vector<int> rank(n+1, 1);
for (int i= 0; i<= n; i++) {
uf[i] = i;
}
vector<int> edge_one;
for (Point e: edge) {
if (e.x == 1) {
edge_one.push_back(e.y);
} else if (e.y == 1) {
edge_one.push_back(e.x);
} else {
union_node(uf, rank, e.x, e.y);
}
}
map<int,int> mmap;
for (int node: edge_one) {
int p = find_parent(uf, node);
if (mmap.find(p) != mmap.end()) {
return "Yes";
}
++mmap[p];
}
return "No";
}
}; class Solution
{
public:
static bool dfs(int depth, int node, vector<vector<int>> &list, vector<bool> &isVisited)
{
if (depth > 2 && node == 1) // 遍历回到第1个节点并且至少走过两条边那表明能走通
{
return true;
}
if(isVisited[node] == true) //如果当前点已经被访问过了则返回false
{
return false;
}
isVisited[node] = true; // 标记这个点已经被访问过了,而且无需恢复现场,因为如果访问过没走通就不可能再走通了
for (int i = 0; i < list[node].size(); i++) // 遍历当前node的所有相连节点
{
int connected_node = list[node][i];
if (dfs(depth + 1, connected_node, list, isVisited))
{
return true;
}
}
return false;
}
string solve(vector<int> ¶m, vector<Point> &edge)
{
int n = param[0]; // 格子个数
int m = param[1]; // 边的个数
vector<vector<int>> list(n + 1); // list[i]表示第i个vector中的所有元素与第i个格子相连(存在边)
vector<bool> isVisited(n + 1, false); // isVisited[i]表示第i个node是否已经被访问过
for (int i = 0; i < m; i++)
{
list[edge[i].x].push_back(edge[i].y);
list[edge[i].y].push_back(edge[i].x);
}
return (dfs(0, 1, list, isVisited) ? "Yes" : "No");
}
}; /**
* struct Point {
* int x;
* int y;
* Point(int xx, int yy) : x(xx), y(yy) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 能回到1号点返回 Yes,否则返回 No
* @param param int整型vector param[0] 为 n,param[1] 为 m
* @param edge Point类vector Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
string solve(vector<int>& param, vector<Point>& edge) {
const int n = param.front(), m = param.back();
vector<vector<int>> g(n + 1);
for (const auto& e : edge) {
g[e.x].emplace_back(e.y);
g[e.y].emplace_back(e.x);
}
function<bool(int, int)> depth_first_search_algorithm = [&](int curr, int prev) -> bool {
if (curr == 1 && prev != -1)
return true;
// ========== 拆路 ========== (因为每条通道只能走一次。!走过的通道就拆掉算了,防止反复走。管它呢!)
if (prev != -1) {
auto it = find(begin(g[curr]), end(g[curr]), prev);
if (it != end(g[curr])) g[curr].erase(it);
it = find(begin(g[prev]), end(g[prev]), curr);
if (it != end(g[prev])) g[prev].erase(it);
}
// ========== 拆路 ==========
for (const int nxt : g[curr])
if (depth_first_search_algorithm(nxt, curr)) return true;
return false;
};
bool ret = depth_first_search_algorithm(1, -1);
return ret ? "Yes" : "No";
}
}; import java.util.*;
public class Solution {
public int n;
public int m;
public String solve (int[] param, Point[] edge) {
if(param.length != 2){
return "No";
}
n = param[0]; //节点
m = param[1]; //边
if(edge.length != m || edge.length == 0){
return "No";
}
boolean res = false;
for(int i = 0; i < m; i++){
if(edge[i].x == 1){
if(edge[i].y == 1){
return "Yes";
}
res = dfs(edge, 1, new boolean[m]);
if(res){
return "Yes";
}
}
}
return "No";
}
public Boolean dfs(Point[] edge, int node, boolean[] visited){
boolean res = false;
for(int j = 0; j < m; j++){
if(!visited[j]){
if(edge[j].x == node){
if(edge[j].y == 1){
return true;
}else{
visited[j] = true;
res = dfs(edge, edge[j].y, visited);
visited[j] = false;
if(res){
return true;
}
}
}
if(edge[j].y == node){
if(edge[j].x == 1){
return true;
}else{
visited[j] = true;
res = dfs(edge, edge[j].x, visited);
visited[j] = false;
if(res){
return true;
}
}
}
}
}
return false;
}
} /*
* function Point(a, b){
* this.x = a || 0;
* this.y = b || 0;
* }
*/
/**
* 能回到1号点返回 Yes,否则返回 No
* @param param int整型一维数组 param[0] 为 n,param[1] 为 m
* @param edge Point类一维数组 Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
var visited = {};
var flag = true;
function solve( param , edge ) {
// write code here
let map = {};
let reachAble = false;
edge.forEach((el)=>{
if(map[el.x] === undefined){
map[el.x] = [el.y];
}else{
map[el.x].push(el.y);
}
if(!reachAble&&el.y===1){
reachAble = true;
}
})
if(!reachAble){
return "No";
}
if(map[1]){
dfs(1,map);
}else{
return "No";
}
if(!flag){
return "Yes";
}
return "No";
}
function dfs(postion,map){
if(postion === 1){
flag = false;
}
if(!flag){
return;
}
let paths = map[postion];
if(!paths){
return;
}
for(let i = 0; i<paths.length;i++){
let po = paths[i];
if(!visited[po]){
visited[po] = true;
dfs(po,map);
}
}
}
module.exports = {
solve : solve
}; import numpy as np
a,b=eval(input())
n=a[0]
m=a[1]
k=np.zeros((m,m))
for i in b:
k[i[0]-1][i[1]-1]=1
# print(k)
j=0
while j<m:
i=0
if k[0][j]>=1:
while i<m:
k[0][i]=k[0][i]+k[j][i]
i+=1
j+=1
# print(k)
if k[0][0]>=1:
print("Yes")
else:
print("No") /**
* 能回到1号点返回 Yes,否则返回 No
*
* @param param int整型一维数组 param[0] 为 n,param[1] 为 m
* @param edge Point类一维数组 Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
boolean[] marked;
int m;
Point[] edge;
public String solve(int[] param, Point[] edge) {
// write code here
m = edge.length;
if (param[1] >= 100000) return "No";
marked = new boolean[m];
this.edge = edge;
for (int i = 0; i < m; i++) {
if (edge[i].x == 1 || edge[i].y == 1) {
if (dfs(edge[i], 1, i, 1)) return "Yes";
}
}
return "No";
}
/**
* 判断是否有回路
* @param point 当前传入的点
* @param len 最大长度
* @param index 当前点的索引坐标
* @param p 上个节点的传入值
* @return 是否有回路
*/
public boolean dfs(Point point, int len, int index, int p) {
if (len == m) return point.y == 1 || point.x == 1;
if (len > 1 && ((point.x == 1) || (point.y) == 1)) return true;
marked[index] = true;
for (int i = 0; i < m; i++) {
if ((edge[i].x == p || p == edge[i].y) && !marked[i]) {
if (edge[i].x == p) {
if (dfs(edge[i], len + 1, i, edge[i].y)) return true;
}
if (edge[i].y == p) {
if (dfs(edge[i], len + 1, i, edge[i].x)) return true;
}
}
}
marked[index] = false;
return false;
} public class Solution {
/**
* 能回到1号点返回 Yes,否则返回 No
* @param param int整型一维数组 param[0] 为 n,param[1] 为 m
* @param edge Point类一维数组 Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
public String solve (int[] param, Point[] edge) {
// write code here
if(param[0] > 100000 || param[1] > 100000){
return "No";
}
int m = param[0];
int[] un = new int[m+1];
union(edge, un);//不包含1的并查集,将较小的作为根
List<Integer> list = new ArrayList<>();
for(Point p : edge){
if(p.x == 1 || p.y == 1){
int another = p.x == 1 ? p.y : p.x;
list.add(another);
}
}
for(int i=0; i<list.size()-1; i++){
for(int j=i+1; j<list.size(); j++){
int un1 = un[list.get(i)] == 0 ? list.get(i) : un[list.get(i)];
int un2 = un[list.get(j)] == 0 ? list.get(j) : un[list.get(j)];
if(un1 == un2){
return "Yes";
}
}
}
return "No";
}
public void union(Point[] edge, int[] un){
for(Point p : edge){
if(p.x == 1 || p.y == 1){
continue;
}else{
int big = Math.max(p.x, p.y);
int small = Math.min(p.x, p.y);
if(un[big] == 0){
un[big] = un[small] == 0 ? small : un[small];
}else{//都有根的需要对根合并
int smallRoot = small;
int bigRoot = un[big];
while(un[smallRoot] != 0){
smallRoot = un[smallRoot];
}
while(un[bigRoot] != 0){
bigRoot = un[bigRoot];
}
if(smallRoot != bigRoot){
un[Math.max(smallRoot, bigRoot)] = Math.min(smallRoot, bigRoot);
}
}
}
}
for(int i=un.length-1; i>=4; i--){//最后一起找根
if(un[i] != 0){
int temp = un[i];
while(un[temp] != 0){
temp = un[temp];
}
un[i] = temp;
}
}
}
}
public class Solution {
/**
* 能回到1号点返回 Yes,否则返回 No
* @param param int整型一维数组 param[0] 为 n,param[1] 为 m
* @param edge Point类一维数组 Point.x , Point.y 分别为一条边的两个点
* @return string字符串
*/
public String solve (int[] param, Point[] edge) {
int n = param[0];
boolean[] visited = new boolean[n+1];
return dfs(1, edge, visited)?"Yes":"No";
}
public boolean dfs(int from, Point[] edge,boolean[] visited) {
int to = 0;
for(int i=0; i<edge.length; i++) {
if(visited[from] || (edge[i].x != from && edge[i].y != from)) continue;
to = edge[i].x == from?edge[i].y:edge[i].x;
visited[from] = true;
if(to == 1 || dfs(to, edge, visited)) return true;
visited[from] = false;
}
return false;
}
} public class Solution { int[] res; public String solve (int[] param, Point[] edge) { int n = param[0],m=param[1]; res = new int[n + 1]; for(int i=0; i<m; i++) { if(union(edge[i].x,edge[i].y)) { return "Yes"; } } return "No"; } public int find(int i) { if(res[i] == 0) return i; return find(res[i]); } public boolean union(int root1,int root2) { if(find(root1) == find(root2)) { if(find(root1) == find(1)) { int next1 = -1,next2 = -1; while(root1 != 1 && res[root1] != 0) { next1 = root1; root1 = res[root1]; } while(root2 != 1 && res[root2] != 0) { next2 = root2; root2 = res[root2]; } if(next1 != next2) return true; } } else { res[root2] = root1; } return false; } }