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, twodimensional array storage;
Note: This is a way of reading. See the topic specifically.
Adjacency list (chain forward star)cin >> n >> m; for (int i=1;i=m;i++) { cin >> i >> j >> x; a[i][j]=a[j][i]=x; }
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:
Another loop is equally important, similar to a query: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; }
Edge table (edge set array)for (int i=linkk[x];i;i=e[i].next)
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:
Traversal of adjacency table dfsdfsdfs: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); }
bfs traversalvoid 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); } }
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
Dijkstrafor (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];
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
Bellmanfordvoid 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]; } }
Supporting negative rings
SPFAint 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 }
The upgraded version of Bellman − fordBellmanfordBellman − ford improves the iteration of Bellman − fordBellmanfordBellman − 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
Kruskalvoid 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<=n1;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); }
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 − 1n1n − 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==n1) //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 ordervoid 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 5Try 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[i1][j],f[i1][j1])+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<=i1;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<=i1;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[i1]+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<=nlen+1;i++) //Left end point { int j=i+len1; //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[i1]); //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[i1][j]+dp[i][j1]; } 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，… ，xm1”X=“x0，x1，… , XM − 1 ", sequence y =" Y0, Y1 ，yk−1”Y=“y0，y1，… ，yk1”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 , k1, 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[i1][j],dp[i][j1]); if (a[i]==b[j]) dp[i][j]=max(dp[i][j],dp[i1][j1]+1); } cout << dp[n][m];