首页 > 代码库 > 数论vs图论

数论vs图论

最近Mayuyu遇到个神奇的数论题目,Mayuyu能做出来真的不容易啊,描述如下。

 

题目:给定一个正整数,满足条件,以为根节点进行扩展,对于每一个节点,它只能到达能整除

     它的节点,如果存在节点,使得成立,则必定会经过点,对于每一个节

     点,有一个值,这个值等于这个节点的最大深度,最后求输出每个节点的序号乘对应值的和。

 

分析:对于一个数,它只能到达它的所有因子,所以第一步就是找出的所有因子,然后就是如果两个因子出现一

     个能整除另一个的情况,就连一条边。最后就构建了一个图,在这个图中,我们从开始进行深度遍历,纪录

     到达点的最大深度值,最后加起来就可以了。这里采用链式前向星处理。

 

代码:

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h>

using namespace std;
const int N = 5005;
typedef long long LL;

int ct,cnt;
LL fac[N];
int head[N];

struct Edge
{
    int to;
    int next;
    int w;
};

Edge edge[N*N];

void Init()
{
    cnt = 0;
    memset(edge,0,sizeof(head));
    memset(head,-1,sizeof(head));
}

void add(int u,int v,int w)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    edge[cnt].w = w;
    head[u] = cnt++;
}

void Find(LL n)
{
    ct = 0;
    LL t = (LL)sqrt(1.0*n);
    for(int i=1; i<=t; i++)
    {
        if(n % i == 0)
        {
            if(i * i == n) fac[ct++] = i;
            else
            {
                fac[ct++] = i;
                fac[ct++] = n / i;
            }
        }
    }
}

void dfs(int u,int dept)
{
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int t = edge[i].to;
        edge[t].w = max(edge[t].w, dept + 1);
        dfs(t,dept+1);
    }
}

int main()
{
    LL n;
    while(cin>>n)
    {
        Find(n);
        Init();
        sort(fac,fac+ct);
        for(int i=0; i<ct; i++)
        {
            for(int j=i+1; j<ct; j++)
                if(fac[j] % fac[i] == 0)
                    add(j,i,0);
        }
        dfs(ct-1,1);
        LL ans = 0;
        for(int i=0; i<ct; i++)
            ans += edge[i].w * fac[i];
        cout<<ans + n<<endl;
    }
    return 0;
}