[algorithm summary] graph theory / dp dynamic programming summary

Written in a corner of konjaku - Z
On February 7, 2020, graph theory and dpdpdp finally come to an end. When I look back, it seems that I have passed a lot Never savor, too much, too much and keep coming to me
This is to commemorate the lost graph theory and dpdpdp;

graph theory

  • Graph storage
    First, the basis of graph theory: storage. Several storage structures are introduced here;
    adjacency matrix
    One of the most simple and violent storage structure, two-dimensional array storage;
    Note: This is a way of reading. See the topic specifically.
     	cin >> n >> m;
    	for (int i=1;i=m;i++)
    	{
    		cin >> i >> j >> x;   
    		a[i][j]=a[j][i]=x;
     	}
    
    Adjacency list (chain forward star)
    Adjacency list, also called chain forward star, is actually the thinking of chain list;
    First, open a linklinklinklinkk array. linkk[i]linkk[i]linkk[i] linkk [i] represents the number of the first edge starting from iii, e e e array stores the edge, e[i].ye[i].ye[i].y represents the end point, e[i].ve[i].ve[i].v represents the weight, e[i].nexte[i].nexte[i].next represents the number of the next edge;
    The core of adjacency table is an insertion function:
    void insert(int x,int y,int v)  //x is the starting point, y is the end point, and v is the weight.
    {  
      e[++t].y=y; e[t].v=v;
      e[t].next=linkk[x]; linkk[x]=t;
    }
    
    Another loop is equally important, similar to a query:
    for (int i=linkk[x];i;i=e[i].next)
    
    Edge table (edge set array)
    A simple storage structure, the idea is also very simple, is to store all the edges in the eee array, to store the start, end, weight.
    struct  node
    {
    	int x,y;  //start and finish
    	int v;    //Weight
    }e[maxm];
    
  • Traversal of Graphs
    dfs traversal
    Adjacency matrix dfsdfsdfs traversal:
    void dfs(int k);
    {
    	printf("%d",k);
    	f[k]=true;
    	for (int i=1;i<=n;i++)
         if (!f[i] && a[k][i])  dfs(i);
    }
    
    Traversal of adjacency table dfsdfsdfs:
    void dfs(int k)
    {
    	for (int i=linkk[k];i;i=e[i].next)
    	 if(!vis[e[i].y]) 
    	 {
    	 	vis[e[i].y]=1;
    	 	dfs(e[i].y);
       }
    }
    
    bfs traversal
    Traversal of adjacency matrix bfsbfsbfs:
    void  bfs(int i);
    {
    	memset(q,0,sizeof(q));
    	int head=1,tail=1;
    	q[1]=i; f[i]=true;
    	while (head<=tail)
    	{
    		k=q[head]; cout>>k;
        	for (int j=1;j<=n,j++)
             if (a[k][j] && !f[j])
             {
      	   		q[++tail]=j;
       			f[j]=true;
             }
            head++;
      	 }	
    }
    
  • shortest path
    Floyd
    Update the shortest path from iii to jjj with kkk as the transfer point
    for (int k=1;k<=n;k++)
      for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
          if  (dis[i][k]+dis[k][j]<dis[i][j])
    	    dis[i][j]=dis[i][k]+dis[k][j];
    
    Dijkstra
    Each time, find a point with the shortest distance from the starting point in the undetermined point, mark it, and use this point as the transit point to update the shortest path of the unmarked point
    Note: DijkstraDijkstraDijkstra does not support negative weight
    void dijkstra(int st);
    {
    	memset(f,0,sizeof(f));
    	memset(dis,0,sizeof(dis));
    	for (int i=1;i<=n;i++) dis[i]=a[st][i];
    	f[st]=1;  dis[st]=0;
    	for (int i=1;i<n;i++)
    	{
        	int min=0xfffffff, k=0;
        	for (int j=1;j<=n;j++)
            	if (!f[j] && (dis[j]<min))  min=dis[j],k=j;
        	if (k==0)  return;  //We can't find the shortest point
        	f[k]=1;  //Add k to set 1;
        	for (int j=1;j<=n;j++)  //The shortest distance of triangle iterative updating
             if (!f[j] && dis[k]+a[k][j]<dis[j])  dis[j]=dis[k]+a[k][j];      
    	}
    }
    
    Bellman-ford
    Supporting negative rings
    int bellman_ford()
    {
    	memset(dis,10,sizeof(dis));  //initial value
    	dis[1]=0;  //The distance from the start point to the start point is 0
    	for (int i=1;i<=n;i++)  //n iterations at most
    	{
    		bool p=0;  //Whether there is slack mark
    		for (int j=1;j<=tot;j++)  //tot edge
    		{
    			int ax=a[j].x,ay=a[j].y,av=a[j].v;  //Article j start, end and length of edge
    			if (dis[ax]+av<dis[ay])  //Triangle iteration
    			{
    				dis[ay]=dis[ax]+av;
    				p=1;  //Relaxation labeling
    			}
    		}
    		if (p==0) return 0;  //No relaxation
    	}
    	return 1;  //Negative ring
    }
    
    SPFA
    The upgraded version of Bellman − fordBellman-fordBellman − ford improves the iteration of Bellman − fordBellman-fordBellman − ford. Each time, as long as you start from the point x x x that was just "relaxed" last time, you can see if $X ¥ can relax other points. Use the queue in BFS to store the points that have just been "relaxed";
    void SPFA(int k)  //SPFA template
    {
    	memset(dis,10,sizeof(dis));  //initial value
    	memset(vis,0,sizeof(vis));  //Clear the tag array. vis[k] indicates whether point K is in the queue
    	dis[k]=0;
    	vis[k]=1;
    	int head=1,tail=1;
    	q[head]=k;  //Point k into the team
    	for (head=1;head<=tail;head++)
    	{
    		int x=q[head];  //Remove team leader
    		for (int i=linkk[x];i>0;i=e[i].next)  //Adjacency table query
    		{
    			if (dis[x]+e[i].v<dis[e[i].y])  //iteration
    			{
    				dis[e[i].y]=dis[x]+e[i].v;
    				if (vis[e[i].y]==0)  //If there is no mark at this point, mark it, enter the team
    				{
    					vis[e[i].y]=1;
    					q[++tail]=e[i].y;
    				}
    			}
    		}
    		vis[x]=0;  //Team out
    	}
    }
    
  • minimum spanning tree
    Prim
    Note: the code given here seeks the sum of the edge weights of the minimum spanning tree
    void prim(int st)  //prim algorithm
    {
    	memset(vis,0,sizeof(vis));
    	memset(dis,0,sizeof(dis));
    	for (int i=1;i<=n;i++) dis[i]=a[st][i];  //Assign crossing edge
    	vis[st]=1; int ans=-1e9;
    	for (int i=1;i<=n-1;i++)
    	{
    		int Min=1e9,mini=0;
    		for (int j=1;j<=n;j++)
    		 if (!vis[j] && dis[j]<Min) Min=dis[j],mini=j;  //Find the nearest point
    		vis[mini]=1;  //sign
    		ans+=dis[mini];  //Sum of accumulated edge weights
    		for (int j=1;j<=n;j++)
    		 if (!vis[j] && dis[j]>a[mini][j])
    		 {
    		 	dis[j]=a[mini][j];  //iteration
    		 }
    	}
    	printf("%d",ans);
    }
    
    Kruskal
    Sort by edge weight from small to large, and then take the edge from small to large in order. You need to use the algorithm of parallel search set to determine whether the added edge (x,y)(x,y)(x,y) forms a ring. If there is a ring, give up the edge, otherwise add the edge (x,y)(x,y)(x,y). If n − 1n-1n − 1 edge has been added, end;
    The most difficult point of Kruskal Kruskal algorithm is how to judge whether a ring is formed after adding edge (x,y)(x,y)(x,y), and whether the two vertices x,y of edge (x,y) (x,y) are connected in the graph. In the Union set, it is only necessary to directly judge whether their father is the same.
    void Kruskal(int k)  //Kruskar
    {
    	for (int i=1;i<=n;i++) father[i]=i;  //The parent node of each start point is itself
    	int cnt=0;
    	for (int i=1;i<=m;i++)
    	{
    		int v=getfather(e[i].x);
    		int u=getfather(e[i].y);
    		if (v!=u)  //Judge whether e[i].x and e[i].y exist in the same set
    		{
    			merge(u,v);  //merge
    			ans+=e[i].v;
    			if (++cnt==n-1)  //End of minimum spanning tree generation
    			{
    				break;
    			}
    		}
    	}
    }
    
  • Topological sort
    Sequence the points of directed acyclic graph;
    Here, the queue is used to maintain the topological order
    void Topsort()  //Topological sort
    {
    	int head=1,tail=0;
    	for (int i=1;i<=n;i++)
      	  if (in[i]==0) q[++tail]=i;  //Initialization
    	for (head=1;head<=tail;head++)
    	{
    		int x=q[head];  //Remove team leader
    		for (int i=linkk[x];i;i=e[i].next)  //Adjacency table query
    		{
    			int y=e[i].y;
    			if (--in[y]==0) q[++tail]=y;  //Join the team
    		}
    		if (tail==n) return;
    	}
    }
    
    Be careful:
    1. The topological sequence of digraphs is not unique;
    2. If there are rings in the graph, there is no topological sequence;
    3. There is also a way to use stack to implement topological sorting.
    

dp

  • Introduction to dp

    knapsack
    specific Poke here
    Recurrence
    Here's an example. Let's not talk about it
    Given a number triangle composed of nnn rows of numbers, as shown in the following figure:
       7
       3 8
       8 1 0
       2 7 4 4
       4 5 2 6 5

    Try to design an algorithm to calculate a path from the top to the bottom of the triangle, so that the total number of the path is the largest (each step can only go from one number to the next layer and its nearest left or right number).

    	for (int i=1;i<=n;i++)
     	 for (int j=1;j<=i;j++)
    	 {
     		cin >> a[i][j];
    	 }
    	for (int i=1;i<=n;i++)
    	 for (int j=1;j<=i;j++)
    	 {
     		f[i][j]=max(f[i-1][j],f[i-1][j-1])+a[i][j];
    	 } 
    

    LCS longest non ascending subsequence and LIS longest non descending subsequence
    There is a classic topic that covers these two issues: missile interception.
    In order to intercept the enemy's attack, scientists have developed a missile system. The missile system has a defect: the first shell can reach any height, but each shell can not be higher than the previous one.
    Now, the height h [i] h [i] h [i] h [i] (H [i] h [i] h [i] is a positive integer of < = 50000 < = 50000 < = 50000), how many missiles can be intercepted by a set of missile intercepting system at most, and how many sets of missile intercepting systems are needed to intercept all missiles?
    Train of thought:
    The first question is obviously a template of LCSLCSLCS;
    The second question is a LISLISLIS template. Why? (konjaku can't purr ~)

    	for (int i=1;i<=n;i++) //LCS
        {
      		dp[i]=1;
      		for (int j=0;j<=i-1;j++)
      	  	  if (h[i]<=h[j]) dp[i]=max(dp[i],dp[j]+1);
      	}
      	int Max=-0xfffffff;
      	for (int i=1;i<=n;i++) Max=max(Max,dp[i]);
      	cout << Max << endl;
    	for (int i=1;i<=n;i++) //LIS
      	{
      		dp[i]=1;
      		for (int j=0;j<=i-1;j++)
      		  if (h[i]>h[j]) dp[i]=max(dp[i],dp[j]+1);
      	}
      	Max=-0xfffffff;
      	for (int i=1;i<=n;i++) Max=max(Max,dp[i]);
      	cout << Max << endl;
    
  • Interval dp

    It seems that it's just a board. Here's a list of the most classic stone merging problems.
    NNN heaps of stones are placed around a circular playground. Now, the stones should be combined into a pile in order. It is stipulated that only 222 adjacent heaps can be combined into a new pile each time, and the number of new heaps of stones should be recorded as the score of this combination.
    An algorithm is designed to calculate the minimum score and the maximum score of the NNN pile stones combined into 111 piles.

    	for (int i=1;i<=n;i++)
      	{
      		cin >> a[i];
      		sum[i]=sum[i-1]+a[i];  //Prefix sum, total number of first i stone piles
      	}
      	memset(f,10,sizeof(f));
      	for (int i=1;i<=n;i++) f[i][i]=0;
      	for (int len=2;len<=n;len++)  //Interval length
      	{
      		for (int i=1;i<=n-len+1;i++)  //Left end point
      		{
      			int j=i+len-1;  //Right endpoint
      			for (int k=i;k<=j;k++)
      		 	 f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);  //The interval optimal value from i to j is updated by the intermediate point k
      		}
      	}
      	cout << f[1][n];
    
  • Two dimensional dp

    Two dimensional dpdpdp, the most classic one is the horse crossing the river. Take this question as an example;
    There is a river crossing pawn at AAA point on the chessboard. You need to go to the target BBB point. Rules of pawn walking: down or right.
    At the same time, there is an opponent's horse at CCC point on the chessboard. The point where the horse is and all the points that can be reached by jumping one step are called the opponent's control points. Therefore, it is called "horse crossing river pawn".
    The chessboard is represented by coordinates, AAA points (0,0) (0,0) (0,0), BBB points (n, m) (n, m (n, m) (n, m (n, M is an integer not more than 151515)), and the position coordinates of the same horse need to be given. Now you are required to calculate the number of paths from AAA point to BBB point, assuming that the position of the horse is fixed, not that the pawn will go one step at a time.

    	scanf("%d %d %d %d",&n,&m,&x,&y);
      	n++;m++;x++;y++;
      	memset(f,0,sizeof(f));
      	for (int i=0;i<=8;i++)
      	{
    		int xx=x+fx[i],yy=y+fy[i];
      		if (xx>=1 && xx<=n && yy>=1 && yy<=m)
      		{
      			f[xx][yy]=1;
      		}
      	}
      	dp[1][1]=1;
      	for (int i=1;i<=n;i++)
      	 for (int j=1;j<=m;j++)
       	  if (f[i][j]==0 && !(i==1 && j==1))
       	  {
    		  dp[i][j]=dp[i-1][j]+dp[i][j-1];
    	  }
      	printf("%d",dp[n][m]);
    
  • Dual process dp

    emm... Take the longest common subsequence.
    The subsequence of character sequence refers to the character sequence formed by randomly (not necessarily continuously) removing several characters (possibly none) from a given character sequence.
    Make the given character sequence X= "x0, x1 ,xm−1”X=“x0,x1,… ,xm-1”X=“x0,x1,… , XM − 1 ", sequence y =" Y0, Y1 ,yk−1”Y=“y0,y1,… ,yk-1”Y=“y0,y1,… , YK − 1 "is a subsequence of XXX. There is a strictly increasing subscript sequence of X, so that for all j=0, 1 , K − 1, with xij=yjj=0, 1 , k-1, xij=yjj=0, 1 , K − 1, with xij=yj.
    For example, X = "ABCBDAB" X = "ABCBDAB" X = "ABCBDAB", Y = "BCDB" Y = "BCDB" Y = "BCDB" is a subsequence of XXX.
    For a given sequence of two characters, find their longest common subsequence.

	while (cin >> ch,ch!='.') a[++n]=ch;
	while (cin >> ch,ch!='.') b[++m]=ch;
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=m;j++)
	 {
	 	dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
	 	if (a[i]==b[j]) dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
	 }
	cout << dp[n][m];
29 original articles published, 33 praised, 3426 visited
Private letter follow

Tags: shell

Posted on Thu, 13 Feb 2020 06:44:00 -0500 by phpfolk2003