Attractor算法代码整理


  1. 建立节点表
  2. 建立边表
  3. 建立节点边表
  4. 交互
  5. 社区发现

1-3为交互做准备
一、建立节点表
EstablishNodeTable(argv[1], ator(argv[3]));

参数:

argv[1]: 表示输入的数据集文件名
ator(argv[3])): 表示数据集边的数量,ator将字符串转为整型数

打开数据集文件

FILE * file = fopen(inputfilename, "r");

对于每个节点i,初始其邻居节点数量为0

int NeighborNumber[NetNodeNum];
for(int i = 0; i < NetNodeNum; i++)
    NeighborNumber[i] = 0;

求每个节点的邻居节点数,用于为指针申请合适空间内存

for(int i=0; i<FileLine; i++)
    fscanf(file,"%d %d", &node_1, &node_2);
    NeighborNumber[node_1-1]++;
    NeighborNumber[node_2-1]++;

建立节点表

for(int i=0; i<FileLine; i++)
    fscanf(file,"%d %d", &node_1, &node_2);
    NodeTable[node_1-1].Pointer[NodeTable[Node_1-1].NodeNum++]=node_2;
    NodeTable[node_2-1].Pointer[NodeTable[Node_2-1].NodeNum++]=node_1;

为每个节点的邻居节点排序(升序)

SortFun(NodeTable[i].Pointer, NodeTable[i].NodeNum);
void SortFun(int *Pointer, int Num) 

采用冒泡排序算法,但设置了“最后改变位置”来确定是否排序完毕

所建节点表如图:
节点表

二、建立边表
EstablishEdgeTable();

求每个节点的边数(每边只保存一次)

for(int loop_i=0; loop_i<NetNodeNum; loop_i++)
    EdgeNumber[loop_i]=0;
    for(int loop_j=0; loop_j<NodeTable[Loop_i].NodeNum; loop_j++)
        if(NodeTable[loop_i].Pointer[loop_j]>loop_i+1)
            EdgeNumber[Loop_i]++;

建立边表

int edgeid = 0; //网络总的边数
for(int loop_i=0; loop_i<NetNodeNum; loop_i++)
{
    int edge_loc_tmp=0;//边表中每个节点的边的下标
    for(int loop_j=0; loop_j<NodeTable[loop_i].NodeNum;loop_j++)
    {
        if(NodeTable[loop_i].Pointer[loop_j]>loop_i+1)
        {
            EdgeWithAttachmentTable[loop_i].Pointer[edge_loc_tmp].n_1_ID=loop_i+1;
         EdgeWithAttachmentTable[loop_i].Pointer[edge_loc_tmp].n_2_ID=NodeTable[loop_i].Pointer[loop_j];           
            EdgeWithAttachmentTable[loop_i].Pointer[edge_loc_tmp].e_ID=edgeid;
            edge_loc_tmp++;
        }
    }
}

所建边表如图:
边表

发现两个节点的共同邻居,以及各自的独有邻居

void FindNeighbors(int node_1, int node_j)
{
    //变量
    int num1=NodeTable[node_i-1].NodeNum;//邻居总数
    int *A1=NodeTable[node_i-1].Pointer; //指向node_i的邻接表的指针
    int num2=NodeTable[node_j-1].NodeNum;
    int *A2=NodeTable[node_j-1].Pointer;
    int p1_loc=0;//表示node_1节点的邻接表下标
    int p2_loc=0;
    int *p1=&A1[0];//p1指向node_i的第一个邻节点
    int *p2=&A2[0];
    int cn_length=0;//共同邻居(邻域)的长度
    int diffa_length=0;//node_i独有邻居的长度
    int diffb_length=0;
    int cn_loc=1;//邻域地址下标,从1开始,0用于保存长度大小
    int diffa_loc=1;
    int diffb_loc=1;

    while(p1_loc<num1 && p2_loc<num2) 
    {
        if(A1[p1_loc]<A2[p2_loc])
        {
            if(A1[p1_loc]!=node_j)
            {
                DiffA[diffa_loc]=A1[p1_loc];
                diffa_length++;
                diffa_loc++;
                p1_loc++;
            }
            else
                p1_loc++;
        }//求node_i的独有邻居

效果如图:
节点1独有邻居

        else if(A1[p1_loc]==A2[p2_loc])
        {
            CN[cn_loc]=A1[p1_loc];
            cn_length++;
            cn_loc++;
            p1_loc++;
            p2_loc++;
        }//求共同邻居

效果如图:
共同邻居

        else
        {
            if(A2[p2_loc]!=node_i)
            {
                DiffB[diffb_loc]=A2[p2_loc];
                diffb_length++;
                diffb_loc++;
                p2_loc++;
            }
            else 
                p2_loc++;
        }//求node_j的独有邻居
    }
}

求剩余独有邻居

    if(p1_loc==num1)
    {
        while(p2_loc<num2)
        {
            if(A2[p2_loc]!=node_i)
            {
                DiffB[diffb_loc]=A2[p2_loc];
                diffb_length++;
                diffb_loc++;
                p2_loc++;
            }
            else
                p2_loc++;
        }//p2_loc余下节点为node_j的独有邻居(node_i除外)
    }

    else 
    {
        while(p1_loc<num1)
        {
            if(A1[p1_loc]!=node_j)
            {
                DiffA[diffa_loc]=A1[p1_loc];
                diffa_length++;
                diffa_loc++;
                p1_loc++;
            }
            else
                p1_loc++;
        }
    }//p1_loc余下节点为node_i的独有邻居(node_j除外)

保存邻居长度

CN[0]=cn_length;
DiffA[0]=diffa_length;
DiffB[0]=diffb_length;

计算每条边的杰卡德距离

    EdgeWithAttachmentTable[i].Pointer[j].dist=1.0-(double)(CN[0]+2)/(double)(CN[0]+DiffA[0]+DiffB[0]+2);

2为边的两端节点

杰卡德距离公式:
杰卡德距离

建立共同邻居的四列二维矩阵,如图:

共同邻居矩阵

    //对于边表中第i个节点的第j条边
    for(int s=1; s<=CN[0];s++)
    {
        int NodeCN=CN[s];
        int Loc_Node_1_R=-1;//node_1和node_CN中最小节点对于id
        int Loc_Node_1_C=-1;//边(node_1,node_CN)对应id(相对于最小节点)
        int Loc_Node_2_R=-1;
        int Loc_Node_2_C=-1;

        int NodeMin=(node_1<NodeCN)?node_1:NodeCN;
        int NodeMax=(node_1>NodeCN)?node_1:NodeCN;
        //求最小节点对应id
        Loc_Node_1_R=NodeMin-1;

        //求边所在id
        for(int loop=0;loop<EdgeWithAttachmentTable[NodeMin-1].EdgeNum;loop++)
            if(EdgeWithAttachmentTable[NodeMin-1].Pointer[loop].n_2_ID==NodeMax)
            {
                Loc_Node_1_C=loop;
                break;
            }
    //同理求Loc_Node_2_R, Loc_Node_2_C

构建二维矩阵

    EdgeWithAttachmentTable[i].Pointer[j].CN_Loc[4*(s-1)+0)=Loc_Node_1_R;
    EdgeWithAttachmentTable[i].Pointer[j].CN_Loc[4*(s-1)+1)=Loc_Node_1_C;
    EdgeWithAttachmentTable[i].Pointer[j].CN_Loc[4*(s-1)+2)=Loc_Node_2_R;
    EdgeWithAttachmentTable[i].Pointer[j].CN_Loc[4*(s-1)+3)=Loc_Node_2_C;

构建node_1独有邻居信息表,如图
独有邻居信息表

    //对于边表中第i个节点的第j条边
    int Edgenum_tmp=0;//保存边(DiffA,node_2)的共同邻居总长度
    for(int s=1;s<=DiffA[0];s++)
    {
        int Node_N_1=DiffA[s];
        //求边(node_N_1,node_2)的共同邻居
        FindCN(Node_N_1, node_2);
        //此时,CN[0]表示Node_N_1和node_2的共同邻居长度

        //求边(DiffA[s],node_2)的共同邻居总长度
        Edgenum_tmp=Edgenum_tmp+CN[0];

        EdgeWithAttachmentTable[i].Pointer[j].N_1_Info[4*(s-1)+0]=Node_N_1;
        EdgeWithAttachmentTable[i].Pointer[j].N_1_Info[4*(s-1)+1]=CN[0];
        //下述求边表中对应行列值的方法同上述共同邻居矩阵表
        EdgeWithAttachmentTable[i].Pointer[j].N_1_Info[4*(s-1)+2]=NodeMin-1;
        EdgeWithAttachmentTable[i].Pointer[j].N_1_Info[4*(s-1)+3]=loop;
    }

构建(DiffA, 其与Node2共同邻居)信息表,如图:
独有共同邻居信息表

Edgenum_tmp=0;
for(int s=1;s<=DiffA[0];s++)
{
    int Node_N_1=DiffA[1];
    FindCN(Node_N_1,node_2);
    //CN[0]表示Node_N_1和node_2的共同邻居长度
    for(int ss=1;ss<=CN[0];ss++)
    {
        int NodeCN=CN[ss];
        int Loc_Node_N_1_R=-1;//(Node_N_1,NodeCN)所在行
        int Loc_Node_N_1_C=-1;//所在列
        int Loc_Node_2_R=-1;
        int Loc_Node_2_C=-1;
        EdgeWithAttachmentTable[i].Pointer[j].N_1_Loc[4*Edgenum_tmp+0]=Loc_Node_N_1_R;  
        EdgeWithAttachmentTable[i].Pointer[j].N_1_Loc[4*Edgenum_tmp+1]=Loc_Node_N_1_C;
        EdgeWithAttachmentTable[i].Pointer[j].N_1_Loc[4*Edgenum_tmp+2]=Loc_Node_2_R;        
        EdgeWithAttachmentTable[i].Pointer[j].N_1_Loc[4*Edgenum_tmp+3]=Loc_Node_2_C;
三、建立节点边表
EstablishEdgesOfNodeTable();

构建节点边表

for(int i=0;i<NetNodeNum;i++)
    for(int j=0;j<EdgeWithAttachmentTable[i].EdgeNum;j++)
    {
        int node_1=EdgeWithAttachmentTable[i].Pointer[j].n_1_ID;
        int node_2=EdgeWithAttachmentTable[i].Pointer[j].n_2_ID;
        EdgesOfNodeTable[node_1_1].Pointer[EdgesOfNodeTable[node_1-1].EdgeNum].Row=i;
        EdgesOfNodeTable[node_1-1].Pointer[EdgesOfNodeTable[node_1-1].EdgeNum].Column=j;
        EdgesOfNodeTable[node_1-1].EdgeNum++;

        EdgesOfNodeTable[node_2-1].Pointer[EdgesOfNodeTable[node_2-1].EdgeNum].Row=i;
        EdgesOfNodeTable[node_2-1].Pointer[EdgesOfNodeTable[node_2-1].EdgeNUm].Column=j;
        EdgesOfNodeTable[node_2-1].EdgeNum++;

效果如图:
节点边表

四、交互
Interaction(BETA, atoi(argv[3]));

边的距离

    double D[NetEdgeNum];//边的距离
    int EdgeLocCount=0;//边的下标

    for(int s_1=0;s_1<NetNodeNum;s_1++)
        for(int s_2=0;s_2<EdgeWithAttachmentTable[s_1].EdgeNum;s_2++)
            D[EdgeLocCount++]=EdgeWithAttachmentTable[s_1].Pointer[s_2].dist;

开始交互

int Terminate=1;//终止条件
int Loop=0;//迭代次数
while(Terminate)
{
    Loop++;
    for(int s_1=0;s_1<NetNodeNum;s_1++)
        for(int s_2=0;s_2<EdgeWithAttachmentTable[s_1].EdgeNum;s_2++)
            if(EdgeWithAttachmentTable[s_1].Pointer[s_2].dist>0 && EdgeWithAttachmentTable[s_1].Pointer[s_2].dist<1)
            {
                EA ThisEA=EdgeWithAttachmentTable[s_1].Pointer[s_2];
                int ThisNode_1=ThisEA.n_1_ID;
                int ThisNode_2=ThisEA.n_2_ID;
                int ThisEdgeId=ThisEA.e_ID;//在总边数中id

                double CI=0.0;//共同邻居的影响
                double N_1_I=0.0;//node_1的独有邻居影响
                double N_2_I-0.0;//node_2的独有邻居影响

共同邻居影响

    for(int s_3=0;s_3<ThisEA.CN_Loc_Length;s_3++)
    {
        double Distance_CI_1;//节点1和共同邻居节点间的距离
        double Distance_CI_2;//节点2和共同邻居节点间的距离
        int *CNLocTmp=ThisEA.CN_Loc;//共同邻居表
        Distance_CI_1=EdgeWithAttachmentTable[CNLocTmp[s_3*4+0]].Pointer[CNLocTmp[s_3*4+1]].dist;
        Distance_CI_2=EdgeWithAttachmentTable[CNLocTmp[s_3*4+2]].Pointer[CNLocTmp[s_3*4+3]].dist;

        int CNTmp_1=EdgeWithAttachmentTable[CNLocTmp[s_3*4+0].Pointer[CNLocTmp[s_3*4+1].n_1_ID;
        int CNTmp_2=EdgeWithAttachmentTable[CNLocTmp[s_3*4+0].Pointer[CNLocTmp[s_3*4+1].n_2_ID;

        int CNTmp_3=(CNTmp_1==ThisNode_1)?CNTmp_2:CNTmp_1;//表示邻居节点

        CI=CI+((double)(1-Distance_CI_2)/(double)NodeTable[ThisNode_1-1].NodeNum)*sin(1-Distance_CI_1);
        CI=CI+((double)(1-Distance_CI_1)/(double)NodeTable[ThisNode_2-1].NodeNum)*sin(1-Distance_CI_2);
    }

说明图:
共同邻居说明图

共同邻居影响CI公式:
CI

节点1独有邻居影响——求lambda

    int s_3=0;
    int s_4=0;//节点1的所有独有邻居与节点2的共同邻居下标
    int s_4_count;//当前独有邻居与节点2的共同邻居下标
    while(s_3<ThisEA.N_1_Info_Length)//节点1的独有邻居长度
    {
        int Ngh_N_1=ThisEA.N_1_Info[s_3*4+0];//节点1独有邻居
        int CN_Num=ThisEA.N_1_Info[s_3*4+1];//Node_N_1和node2的共同邻居长度
        double Distance_N_N_1=EdgeWithAttachmentTable[ThisEA.N_1_Info[s_3*4+2]].Pointer[ThisEA.N_1_Info[s_3*4+3]].dist;

        s_4_count=s_4;
        double lambda_numerator=0;//lambda的分子
        //求的是当前独有邻居与共同邻居的相似度之和之和+节点2与共同邻居的相似度之和
        for(s_4=s_4_count;s_4<s_4_count+CN_Num;s_4++)
        {
            int loc_1;
            int loc_2;
            loc_1=ThisEA.N_1_Loc[s_4*4+0];//(Node_N_1,NodeCN)所在行
            loc_2=ThisEA.N_1_Loc[s_4*4+1];//(Node_N_1,NodeCN)所在列
            lambda_numerator=lambda_numerator+(1-EdgeWithAttachmentTable[loc_1].Pointer[loc_2].dist);

            loc_1=ThisEA.N_1_Loc[s_4*4+2];//(node2,NodeCN)所在行
            loc_2=ThisEA.N_1_Loc[s_4*4+3];//(node2,NodeCN)所在列
            lambda_numerator=lambda_numerator+(1-EdgeWithAttachmentTable[loc_1].Pointer[loc_2].dist);
        }

        double lambda_denominator=0;//lambda的分母
        //求的是当前独有邻居的所有边的相似度之和
        for(int s_5=0;s_5<EdgesOfNodeTable[Ngh_N_1].EdgeNum;s_5++)
        {
            int loc_r=EdgesOfNodeTable[Ngh_N_1].Pointer[s_5].Row;
            int loc_c=EdgesOfNodeTable[Ngh_N_1].Pointer[s_5].Column;
            lambda_denominator=lambda_denominator+(1-EdgeWithAttachmentTable[loc_r].Pointer[loc_c].dist);
        }

        double lambda=(double)lambda_numerator/(double)lambda_denominator;

说明图:
独有邻居说明图
lambda公式:
lambda公式

节点1独有邻居影响

        double parameter=(lambda>beta)?1:-1;
        if(parameter==1)
            N_1_I=N_1_I+parameter*lambda/(double)NodeTable[ThisNode_1-1].NodeNum*sin(1-Distance_N_N_1);
        else
            N_1_I=N_1_I+parameter*(beta-lambda)/(double)NodeTable[ThisNode_1-1].NodeNum*sin(1-Distance_N_N_1);
        s_3++;//node1独有邻居下标
    }

独有邻居影响EI公式:
独有邻居影响EI

三种交互模式总影响

    D[ThisEdgeId] = D[ThisEdgeId]+(-(N_1_I+N_2_I)-(((double)1.0/(double)NodeTable[ThisNode_1-1].NodeNum+(double)1.0/(double)NodeTable[ThisNode_2-1].NodeNum)*sin(1-ThisEA.dist) +CI));

    if(D[ThisEdgeId]<0)
        D[ThisEdgeId]=0;
    if(D[ThisEdgeId]>1)
        D[ThisEdgeId]=1;
}

三种交互模式总影响公式:
总影响

终止迭代判断

double sum_1=0;//网络中每条边的距离之和
double sum_2=0;//更新后每条边的距离之和
int EdgeCounter=0;
for(int s_1=0;s_1<NetNodeNum;s_1++)
    for(int s_2=0;s_2<EdgeWithAttachmentTable[s_1].EdgeNum;s_2++)
    {
        sum_1=sum_1+EdgeWithAttachmentTable[s_1].Pointer[s_2].dist;
        sum_2=sum_2+D[EdgeCounter];
        EdgeCounter++;
    }
    if(sum_1==sum_2||Loop>1000)
        Terminate=0;//结束迭代

更新距离

EdgeCounter=0;
for(int s_1=0;s_1<NetNodeNum;s_1++)
    for(int s_2=0;s_2<EdgeWithAttachmentTable[s_1].EdgeNum;s_2++)
    {
        EdgeWithAttachmentTable[s_1].Pointer[s_2].dist=D[EdgeCounter];
        EdgeCounter++;
    }
五、发现社区并输出结果
FindClusters(argv[2]);

建立新的节点表,距离等于1的边(邻居节点)不在考虑范围内

结合队列,通过广度优先搜索算法发现簇

int clusters[NetNodeNum+1];//每个节点所在簇,cluster[0]未被使用
for(int k=0;k<=NetNodeNum;k++)
    clusters[k]=-1;
int Q[NetNodeNum];//队列
int ClusterID=1;//簇的值,从1开始
int Terminate=1;//终止条件

while(Terminate){
    Terminate = 0;  
    int id;
    for(id=1; id<=NetNodeNum; id++)
        if(clusters[id]==-1) 
        {//开始每个节点的簇均为-1,表示该节点尚未分簇
            Terminate = 1;//有尚未分簇的节点便不能终止循环
            clusters[id] = ClusterID;//开始,网络中第一个节点所在簇为1   
            Q[0] = id;//插入队列,last从-1到0
            int first=-1;
            int last = 0;  //队尾     
            int v;
            while(first!=last)
            {  //队列不为空
                v = Q[++first];  //出队列保存到v
                for(int len=0; len<NodeTable_New[v-1].NodeNum; len++) {
                    int RelatedNode = NodeTable_New[v-1].Pointer[len];
                        if(clusters[RelatedNode]==-1) 
                        {
                            Q[++last] = RelatedNode; //入队列
                            clusters[RelatedNode] = ClusterID;
                        }
                }
            }
            ClusterID = ClusterID + 1;
        }
}

// 【将簇保存在二维数组】
FILE * fout = fopen(outputfile,"w");
if(fout==NULL)
    printf("opening outputfile fails\n"); exit(0);
for(int i=1; i<=NetNodeNum; i++)
    fprintf(fout, "%d %d\n", i, clusters[i]);//网络节点所在簇
fclose(fout);

说明图
社区发现

Algorithms   本次README修订为算法仓库Algorithms的第100次commit,首先我们庆祝自2016年8月4日本仓库建立以来Dev-XYS在算法学习方面取得的显著进步!   这里有各种算法的C++代码,任何人可以在自己的任何程序中使用,欢迎大家指出代码中的错误以及有待改进的地方。   本仓库内所有代码的授权方式为Unlicense,大家如果使用我的代码开发自己的软件挣了大钱,或是参考我的代码在NOI中得了金牌,我都会很高兴的。使用这里的代码之后,你可以自主选择是否公开源代码。总而言之,你可以把这里的代码当作你自己写的一样,无论怎样使用都是被允许的。但是,我不对本仓库内代码的正确性负责。大家要是使用我的代码开发软件而导致程序崩溃,或是参考我的代码在考试时出错,请不要向我抱怨。如果你愿意,遇到问题可以在Issues中提出来,我们共同解决。我们不赞成Pull Request,因为本仓库主要储存作者已经学习的算法,全部代码均由作者本人负责维护与更新。   以下索引提供了本仓库内算法的中文名,方便大家查找。更新可能有很长时间的延迟,不保证所有算法的名称都在列表中出现。 Index --------------------------Contents-------------------------- --------------------------FileName-------------------------- AC自动机 Aho-Corasick-Automation 单源最短路径(SPFA) Bellman-Ford(Queue-Optimised) 单源最短路径(Bellman-Ford) Bellman-Ford 使用Edmonds-Karp进行二分图匹配 Bigrpah-Matching(Edmonds-Karp) 普通的二叉搜索树 Binary-Search-Tree 广度优先搜索 Breadth-First-Search 冒泡排序 Bubble-Sort 桶排序 Bucket-Sort 组合数的递推求解 Combination(Recursion) 枚举组合 Combination 基本的复数类 Complex-Number 割点 Cut-Vertex 深度优先搜索 Depth-First-Search 堆优化的Dijkstra算法 Dijkstra(Heap-Optimised) 并查集 Disjoint-Set-Union 最大流Edmonds-Karp算法 Edmonds-Karp 欧拉函数 Euler's-Totient-Function 有向图的欧拉回路 Eulerian-Tour(Digraph) 拓展欧几里得算法 Extended-Euclid 简单的快速幂 Fast-Exponentiation 树状数组 Fenwick-Tree 所有结点对之间的最短路径(Floyd) Floyd-Warshall 凸包算法(Graham扫描法) Graham-Scan 辗转相除法求最大公约数 Greatest-Common-Divisor 堆排序 Heap-Sort ISAP算法 Improved-Shortest-Augmenting-Path(Naive) 插入排序 Insertion-Sort 字符串匹配(KMP) Knuth-Morris-Pratt 最小生成树(Kruskal) Kruskal 最近公共祖先(Tarjan) Least-Common-Ancestor(Tarjan) 使用后缀数组求解最长公共子串 Longest-Common-Substring 最长上升子序列(n·log(n)) Longest-Increasing-Subsequence(n·log(n)) 倍增法求最近公共祖先 Lowest-Common-Ancestor(Doubling) 朴素的矩阵乘法 Matrix-Multiplication(Naive) 归并排序 Merge-Sort 最小堆 Min-Heap 乘法逆元 Modular-Multiplicative-Inverse 仅支持单点修改的可持久化线段树(维护区间和值) Persistent-Segment-Tree(Sum) 试除法素数测试 Prime-Check(Naive) 线性的素数筛法 Prime-Sieve(Linear) 队列的基本操作 Queue 快速排序的优化版本 Quick-Sort(Extra-Optimised) 快速排序的随机化版本 Quick-Sort(Randomized) 快速排序 Quick-Sort 使用向量叉积判断两个有向线段的时针关系 Segment-Direction 线段树维护区间最大值 Segment-Tree(Maximum) 线段树维护区间最小值 Segment-Tree(Minimum) 线段树维护区间和值 Segment-Tree(Sum) 普通的选择算法 Selection Eratosthenes素数筛法 Sieve-of-Erotosthenes 指针版的单向链表 Singly-Linked-List(Pointer) 跳表 Skip-List ST表 Sparse-Table 伸展树 Splay 博弈论SG函数 Sprague-Grundy 栈的基本操作 Stack 递推法求解无符号第一类斯特林数 Stirling-Number(Cycle,Unsigned,Recursion) 递推法求解第二类斯特林数 Stirling-Number(Subset,Recursion) 倍增法求解后缀数组 Suffix-Array(Doubling) 倍增法求解后缀数组(附带Height数组) Suffix-Array-with-Height(Doubling) 使用Tarjan算法求解强连通分量 Tarjan(Strongly-Connected-Components) 数组版的字典树 Trie(Array) 指针版的字典树 Trie(Pointer)
目录 目录 1 Graph 图论 3 | DAG 的深度优先搜索标记 3 | 无向图找桥 3 | 无向图连通度(割) 3 | 最大团问题 DP + DFS 3 | 欧拉路径 O(E) 3 | DIJKSTRA 数组实现 O(N^2) 3 | DIJKSTRA O(E * LOG E) 4 | BELLMANFORD 单源最短路 O(VE) 4 | SPFA(SHORTEST PATH FASTER ALGORITHM) 4 | 第 K 短路(DIJKSTRA) 5 | 第 K 短路(A*) 5 | PRIM 求 MST 6 | 次小生成树 O(V^2) 6 | 最小生成森林问题(K 颗树)O(MLOGM). 6 | 有向图最小树形图 6 | MINIMAL STEINER TREE 6 | TARJAN 强连通分量 7 | 弦图判断 7 | 弦图的 PERFECT ELIMINATION 点排列 7 | 稳定婚姻问题 O(N^2) 7 | 拓扑排序 8 | 无向图连通分支(DFS/BFS 邻接阵) 8 | 有向图强连通分支(DFS/BFS 邻接阵)O(N^2) 8 | 有向图最小点基(邻接阵)O(N^2) 9 | FLOYD 求最小环 9 | 2-SAT 问题 9 Network 网络流 11 | 二分图匹配(匈牙利算法 DFS 实现) 11 | 二分图匹配(匈牙利算法 BFS 实现) 11 | 二分图匹配(HOPCROFT-CARP 的算法) 11 | 二分图最佳匹配(KUHN MUNKRAS 算法 O(M*M*N)) 11 | 无向图最小割 O(N^3) 12 | 有上下界的最小(最大)流 12 | DINIC 最大流 O(V^2 * E) 12 | HLPP 最大流 O(V^3) 13 | 最小费用流 O(V * E * F) 13 | 最小费用流 O(V^2 * F) 14 | 最佳边割集 15 | 最佳点割集 15 | 最小边割集 15 | 最小点割集(点连通度) 16 | 最小路径覆盖 O(N^3) 16 | 最小点集覆盖 16 Structure 数据结构 17 | 求某天是星期几 17 | 左偏树 合并复杂度 O(LOG N) 17 | 树状数组 17 | 二维树状数组 17 | TRIE 树(K 叉) 17 | TRIE 树(左儿子又兄弟) 18 | 后缀数组 O(N * LOG N) 18 | 后缀数组 O(N) 18 | RMQ 离线算法 O(N*LOGN)+O(1) 19 | RMQ(RANGE MINIMUM/MAXIMUM QUERY)-ST 算法 (O(NLOGN + Q)) 19 | RMQ 离线算法 O(N*LOGN)+O(1)求解 LCA 19 | LCA 离线算法 O(E)+O(1) 20 | 带权值的并查集 20 | 快速排序 20 | 2 台机器工作调度 20 | 比较高效的大数 20 | 普通的大数运算 21 | 最长公共递增子序列 O(N^2) 22 | 0-1 分数规划 22 | 最长有序子序列(递增/递减/非递增/非递减) 22 | 最长公共子序列 23 | 最少找硬币问题(贪心策略-深搜实现) 23 | 棋盘分割 23 | 汉诺塔 23 | STL 中的 PRIORITY_QUEUE 24 | 堆栈 24 | 区间最大频率 24 | 取第 K 个元素 25 | 归并排序求逆序数 25 | 逆序数推排列数 25 | 二分查找 25 | 二分查找(大于等于 V 的第一个值) 25 | 所有数位相加 25 Number 数论 26 1 |递推求欧拉函数 PHI(I) 26 |单独求欧拉函数 PHI(X) 26 | GCD 最大公约数 26 | 快速 GCD 26 | 扩展 GCD 26 | 模线性方程 A * X = B (% N) 26 | 模线性方程组 26 | 筛素数 [1..N] 26 | 高效求小范围素数 [1..N] 26 | 随机素数测试(伪素数原理) 26 | 组合数学相关 26 | POLYA 计数 27 | 组合数 C(N, R) 27 | 最大 1 矩阵 27 | 约瑟夫环问题(数学方法) 27 | 约瑟夫环问题(数组模拟) 27 | 取石子游戏 1 27 | 集合划分问题 27 | 大数平方根(字符串数组表示) 28 | 大数取模的二进制方法 28 | 线性方程组 A[][]X[]=B[] 28 | 追赶法解周期性方程 28 | 阶乘最后非零位,复杂度 O(NLOGN) 29 递归方法求解排列组合问题 30 | 类循环排列 30 | 全排列 30 | 不重复排列 30 | 全组合 31 | 不重复组合 31 | 应用 31 模式串匹配问题总结 32 | 字符串 HASH 32 | KMP 匹配算法 O(M+N) 32 | KARP-RABIN 字符串匹配 32 | 基于 KARP-RABIN 的字符块匹配 32 | 函数名: STRSTR 32 | BM 算法的改进的算法 SUNDAY ALGORITHM 32 | 最短公共祖先(两个长字符串) 33 | 最短公共祖先(多个短字符串) 33 Geometry 计算几何 34 | GRAHAM 求凸包 O(N * LOGN) 34 | 判断线段相交 34 | 求多边形重心 34 | 三角形几个重要的点 34 | 平面最近点对 O(N * LOGN) 34 | LIUCTIC 的计算几何库 35 | 求平面上两点之间的距离 35 | (P1-P0)*(P2-P0)的叉积 35 | 确定两条线段是否相交 35 | 判断点 P 是否在线段 L 上 35 | 判断两个点是否相等 35 | 线段相交判断函数 35 | 判断点 Q 是否在多边形内 35 | 计算多边形的面积 35 | 解二次方程 AX^2+BX+C=0 36 | 计算直线的一般式 AX+BY+C=0 36 | 点到直线距离 36 | 直线与圆的交点,已知直线与圆相交 36 | 点是否在射线的正向 36 | 射线与圆的第一个交点 36 | 求点 P1 关于直线 LN 的对称点 P2 36 | 两直线夹角(弧度) 36 ACM/ICPC 竞赛之 STL 37 ACM/ICPC 竞赛之 STL 简介 37 ACM/ICPC 竞赛之 STL--PAIR 37 ACM/ICPC 竞赛之 STL--VECTOR 37 ACM/ICPC 竞赛之 STL--ITERATOR 简介 38 ACM/ICPC 竞赛之 STL--STRING 38 ACM/ICPC 竞赛之 STL--STACK/QUEUE 38 ACM/ICPC 竞赛之 STL--MAP 40 ACM/ICPC 竞赛之 STL--ALGORITHM 40 STL IN ACM 41 头文件 42 线段树 43 求矩形并的面积(线段树+离散化+扫描线) 43 求矩形并的周长(线段树+离散化+扫描线) 44
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值