PTA -- the team's "food chain" -- the second algorithm exercise of DS&A course practice

Posted by lightpace on Wed, 23 Feb 2022 04:33:57 +0100

1, Title

2, Topic analysis

  1. The data structure of the graph needs to be used, and it is a directed graph. It is simpler to use the adjacency table. The adjacency table can be implemented by itself or by STL map+vector. I prefer to use the vector array, which is simple and convenient, but the graph in the question may have repeated directed edges, which we don't need, and finally we need to find the ring with the smallest dictionary order, At the beginning, the edge is de duplicated and the edge table sequence is sorted from small to large, so the set container (automatic sorting and de duplication) is adopted
  2. To find a directed ring containing all nodes in a graph
  3. The direct idea is DFS, but ordinary DFS directly traverses all nodes at one time and ends when it returns to the starting node. It can't guarantee that each path can be searched. Transform it. When searching deeply, store the traversed nodes in the result array, mark the visited nodes, and spit out the traversed nodes when returning upward, It is to delete from the result array and mark it as not accessed, so as to find another path through the node
  4. In the next process, judge whether all nodes have been traversed every time you reach a node, and the last node of the result array can reach the starting node, then the sequence meets the requirements
  5. Loop through all nodes and enter DFS as the starting node. Since the side table is sorted at the beginning, the first ring that meets the conditions can be found and ended. Return
  6. At first, I wanted to use stack to realize that the tail of the sequence is increasing and deleted, but I need to traverse the output ring when I find the sequence. Stack can't simply traverse, so I use the array to imitate the stack container that can be traversed
    As a result, it timed out, and some details were not taken into account
    Analyze the timeout reason of the fourth test point and prune DFS
    Special attention
    (1) I feel that it is not fast enough to judge whether the following figure is connected or not at the beginning. Because the self-made DFS will find all the rings, I only need DFS once to judge whether it is connected and write a DFS
    (2) Judge the remaining nodes that have not been accessed every time. If the remaining nodes do not reach the edge of the starting node, the ring will not work. Go back

3, Source code

#include<bits/stdc++.h>
using namespace std;
#define MAXSIZE 22
set<int>G[MAXSIZE];
int n,now;
bool visited[MAXSIZE];
int ans[MAXSIZE]; 
bool f;    //Mark whether the result ring is found 
void dfs(int i)   //Basic dfs for judging whether a graph is connected 
{
	visited[i]=true;
	for(set<int>::iterator it=G[i].begin();it!=G[i].end();it++)
	{
		if(!visited[*it]) 
		{
			dfs(*it);	
		}
		
	}
}
void my_dfs(int i)
{
	if(f) return ;
	visited[i]=true;
	now++;
	ans[now]=i;  //Save the current node into the result array 
	if(now==n&&G[ans[now]].count(ans[1])) //After traversing all nodes, judge whether the last node can reach the starting node 
	{
		f=true;  //If you find a sequence, mark the output, and you don't have to continue with the rest 
		printf("%d",ans[1]);
		for(int i=2;i<=now;i++)
		{
			printf(" %d",ans[i]);
	 	}
		return ;
	}
	
	bool last=false;   //Judge whether the node that has not been visited can reach the starting node 
	for(int j=1;j<=n;j++)
	{
		if(!visited[j]&&G[j].count(ans[1])) 
		{
			last=true;
			break;
		}
	}
	if(!last)  return ;
	
	for(set<int>::iterator it=G[i].begin();it!=G[i].end();it++)
	{
		int t=(*it);
		//cout<<t<<"  "<<endl;
		if(!visited[t]) 
		{
			my_dfs(t);
			visited[t]=false;  //dfs fallback, delete the node from the result ring and find another ring 
			now--;	
		}
		
	}
}

bool Find_List()
{
	for(int j=1;j<=n;j++)  visited[j]=false;
	dfs(1);  //First judge whether the figure below is connected 
	for(int j=1;j<=n;j++) 
	{
		if(!visited[j]) return false;//The graph is not connected at all and ends directly
	}
	for(int i=1;i<=n;i++)   //Find the ring from the smallest node and make each node the starting node 
	{
		for(int j=1;j<=n;j++)  visited[j]=false;
		now=0;
		my_dfs(i);
		if(f) return true;
	}
	return false;
}
int main()
{
	scanf("%d",&n);
	char c;
	f=false;
	for(int i=1;i<=n;i++)   //Read graph into set 
	{
		for(int j=1;j<=n;j++)
		{
			cin>>c;
			if(c=='W') G[i].insert(j);
			else if(c=='L')  G[j].insert(i);
		}
	}
	
	if(!Find_List())  printf("No Solution");
	return 0;
}
/*
5     //Simulate an unconnected graph
-DDDD
D-DWL
DD-DW
DDW-D
DDDD-


*/

I'm a little wordy. You can refer to the following blog
https://blog.csdn.net/Morzker/article/details/102537956

1. When writing code, simulate the process of dfs and think about how to improve the code to achieve the desired effect
2. Find a way to prune the timeout dfs. Sometimes there is no need to recurse after reaching a node. Recursion is very time-consuming and can be handled separately for special graphs (disconnected)
3. When the sequence is the smallest, try to sort the nodes at the beginning, so that if you find one that meets the requirements in the traversal process, you can directly output and end the program

Topics: Algorithm data structure