# [algorithm summary] graph theory / dp dynamic programming summary

### graph theory

• ##### Graph storage
First, the basis of graph theory: storage. Several storage structures are introduced here;
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, also called chain forward star, is actually the thinking of chain list;
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;
}
```
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
```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);
}
```
```void dfs(int k)
{
if(!vis[e[i].y])
{
vis[e[i].y]=1;
dfs(e[i].y);
}
}
```
bfs traversal
```void  bfs(int i);
{
memset(q,0,sizeof(q));
q=i; f[i]=true;
{
for (int j=1;j<=n,j++)
if (a[k][j] && !f[j])
{
q[++tail]=j;
f[j]=true;
}
}
}
```
• ##### 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
```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=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;
q[head]=k;  //Point k into the team
{
{
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
{
for (int i=1;i<=n;i++)
if (in[i]==0) q[++tail]=i;  //Initialization
{
{
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[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;
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

Tags: shell

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