目录
一:kruskal算法(最小生成树)
二:prim算法
三:KMP算法
1:理解
如图,要求找到一条最短的路径。我们先从最小的数1开始,1->2为1,1->3为2,4->6为3,6->5为4,2->3注意2和3这两个端点都被连接了,也就是说2->3可以通过2->1->3.同理4->5也不行,3->4为9可以,当数量达到总数-1时路便通了。
此时变成
步骤:1,先把长度从小到大排序。2,查找两个点是否都连接了,3,到n-1的时候输出。
注意:排序使用快排,查找使用查并集。
1,排序
void kp(int l,int r)//从大到小进行快排
{struct fun t;
if(l>r)
return;
int i=l,j=r;
while(i!=j)
{
while(kk[j].c>=kk[l].c&&i
2,查找
void csh(int q)//初始化
{
for(int i=1;i<=q;i++)
x[i]=i;
}
int find(int i)//查找
{
if(x[i]==i) return i;
x[i]=find(x[i]);return x[i];
}
int hp(int i,int j)//合并并判断
{
if(find(i)!=find(j))
{x[j]=i;return 1;}
return 0;
}
3,kruskal核心算法
for(int i=1;i<=m;i++)//核心算法
{
if(hp(kk[i].a,kk[i].b))
{
c++;sum+=kk[i].c;
}
if(c==n-1) break;
}
完整代码:
#include
using namespace std;
#define N 100
int x[100];
struct fun
{
int a,b,c;
}kk[N];
void kp(int l,int r)//从大到小进行快排
{struct fun t;
if(l>r)
return;
int i=l,j=r;
while(i!=j)
{
while(kk[j].c>=kk[l].c&&i>n>>m;
csh(n);
for(int i=1;i<=m;i++)
{
cin>>kk[i].a>>kk[i].b>>kk[i].c;
}
kp(1,m);
for(int i=1;i<=m;i++)//核心算法
{
if(hp(kk[i].a,kk[i].b))
{
c++;sum+=kk[i].c;
}
if(c==n-1) break;
}
cout<
1,理解:
还是这张图,求最短路径。这里我们随便选一个点1,离他最近的点是2,那么1和2看成一个集合,离着个集合最近的点是3,123又成一个集合,同理找到4,6,5。sum=1+2+9+3+4=19.
注意:找点的时候要找孤立的点。
这里把每两点距离进行初始化
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) e[i][j]=0;
else e[i][j]=inf;
在存储的时候要反向再储存一遍
for(i=1;i<=m;i++)
{
cin>>t1>>t2>>t3;
e[t1][t2]=t3;//无向图,需要反向再储存一遍
e[t2][t1]=t3;
}
初始化1号顶点到每个点的距离,就是我们说的集合处理找最短
for(i=1;i<=n;i++)//初始化,1号顶点到各个顶点的距离
dis[i]=e[1][i];
核心
book[1]=1;//标记是否一个顶点已经加入树
c++;
while(ce[j][k])
dis[k]=e[j][k];
}
}
cout<
完整代码
#include
using namespace std;
int main()
{
int n,m,i,j,k,min,t1,t2,t3;
int e[7][7],dis[7],book[7]={0};
int inf=99999999;//储存一个无穷值
int c=0,sum=0;//c用来记录树中顶的个数,sum储存路径和
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) e[i][j]=0;
else e[i][j]=inf;
for(i=1;i<=m;i++)
{
cin>>t1>>t2>>t3;
e[t1][t2]=t3;//无向图,需要反向再储存一遍
e[t2][t1]=t3;
}
for(i=1;i<=n;i++)//初始化,1号顶点到各个顶点的距离
dis[i]=e[1][i];
book[1]=1;//标记是否一个顶点已经加入树
c++;
while(ce[j][k])
dis[k]=e[j][k];
}
}
cout<
字符串查找问题。
首先,我们得知道部分匹配值(数组next)。部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。
以ABCDABD为例。
"A"的前缀和后缀都为空集,共有元素的长度为0;
"AB"的前缀为[A],后缀为[B],共有元素的长度为0;
"ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
"ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
"ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;
"ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;
"ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。
那么知道了部分匹配值,这有一个公式:移动位数 = 已匹配的字符数 - 对应的部分匹配值
以字符串:BBC ABCDAB ABCDABCDABDE为例 ,子链:ABCDABD
next(部分匹配值)
for(int i=2;i<=len2;i++)//next数组处理
{
while(i1&&str2[i1+1]!=str2[i])//如果str2[i1+1]!=str2[i]那么这串连续的相等断了,所以无法继承之前的情况
{
i1=n[i1];//顺着next我们可以找到能够让我们继续匹配的值,但i1不能为0并且如果我们找到了str2[i1+1]==str2[i]的地方,那么就可以从这里开始继承
}
if(str2[i1+1]==str2[i])
{
i1++;//相等就比下一个,同时这也是计数+1
}
n[i]=i1;//把算出的值给next
}
代码
#include
using namespace std;
char str1[1000005],str2[1000005];
int len1,len2,i1;
int n[1000005];
int main()
{
scanf("%s %s",str1+1,str2+1);
len1=strlen(str1+1);
len2=strlen(str2+1);
for(int i=2;i<=len2;i++)//next数组处理
{
while(i1&&str2[i1+1]!=str2[i])//如果str2[i1+1]!=str2[i]那么这串连续的相等断了,所以无法继承之前的情况
{
i1=n[i1];//顺着next我们可以找到能够让我们继续匹配的值,但i1不能为0并且如果我们找到了str2[i1+1]==str2[i]的地方,那么就可以从这里开始继承
}
if(str2[i1+1]==str2[i])
{
i1++;//相等就比下一个,同时这也是计数+1
}
n[i]=i1;//把算出的值给next
}
i1=0;//初始化
for(int i=1;i<=len1;i++)//和求next差不多
{
while(i1&&str2[i1+1]!=str1[i])
{
i1=n[i1];
}
if(str2[i1+1]==str1[i])
{
i1++;
}
if(i1==len2)
{
printf("%d\n",i-len2+1);//输出str2在str1中出现的位置
i1=n[i1];
}
}
for(int i=1;i<=len2;i++)
printf("%d ",n[i]);
}