社交树 题解

题目id:20316

题目描述

有一句话叫作:“最多只需要\(7\)个人就可以认识任何人”,因为每个人都有自己的朋友,而朋友也有自己的朋友,所以在这世界上的任何一个陌生人,可能都是你朋友的朋友的朋友的朋友的朋友的朋友的朋友。当然这并不意味着我们和任何一个陌生人建立联系很容易,通过朋友来找朋友往往需要花费不小的代价。现在你只有一个朋友,但你的朋友却有很多他的朋友(朋友是相互的,你也是他的朋友)。你和朋友进行联络需要付出一定的代价,同样的你朋友联络他的朋友也有一定的代价。给你所有的人和每个人的朋友关系,求出你联络他们每个人所需要的代价。

解题思路

本题解法较多,本文仅介绍最短路算法和DFS算法。

1.最短路算法

虽然这是一颗树,但我们还是可以用图的最短路算法解决此题。
假设\(\left(x,y\right)\)是一对朋友,他们联系对方花费的代价为\(p_x\)\(p_y\),那我们可以建两条有向边分别连接对方,权值分别为\(p_y\)\(p_x\)
然后跑一遍最短路就行了,由于题目求的是根节点到各个节点的距离,因此该题可以用单源最短路径过(我们班还有个用\(Floyd\)过的)
本蒟蒻忘了\(dijkstra\)算法板子,只好写了个\(SPFA\)献丑(别说我凡尔赛真的不会!)
如果不太了解最短路,可以看一下OI Wiki的介绍。

void spfa()
{
    queue<int>q;
    q.push(1);
    vis[1]=1;
    memset(dis,127,sizeof(dis));
    dis[1]=a[1];
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=0;i<v[u].size();++i)
            if(dis[u]+v[u][i].second<dis[v[u][i].first])
            {
                dis[v[u][i].first]=dis[u]+v[u][i].second;
                if(!vis[v[u][i].first])
                {
                    q.push(v[u][i].first);
                    vis[v[u][i].first]=1;
                }
            }
    }
}

这里需要注意的是,\(dis_1\)一定要赋值\(a_1\)!我们班有个大聪明赋的\(1\)\(\textcolor[RGB]{82,196,26}{AC}\)到全\(\textcolor[RGB]{231,76,60}{WA}\),白白丢了\(100\)分(他写的是DFS)。

最短路算法 AC Code

#include<bits/stdc++.h>
#define N 1000007
#define INF 1e18
#define MOD 1000000007
#define LL long long
#define pb push_back
#define lb long double
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define IOS ios::sync_with_stdio(0),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
LL n,a[5005],dis[5005];
bool vis[5005];
vector<pair<LL,LL>>v[5005];
int main()
{
    IOS;
    cin>>n;
    for(int i=1;i<=n;++i)
        cin>>a[i];
    for(int i=1,x,y;i<n;++i)
    {
        cin>>x>>y;
        v[x].pb({y,a[y]});
        v[y].pb({x,a[x]});
    }
    queue<LL>q;
    q.push(1);
    vis[1]=1;
    memset(dis,127,sizeof(dis));
    dis[1]=a[1];//千万记得赋值a[1]!
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=0;i<v[u].size();++i)
            if(dis[u]+v[u][i].second<dis[v[u][i].first])
            {
                dis[v[u][i].first]=dis[u]+v[u][i].second;
                if(!vis[v[u][i].first])
                {
                    q.push(v[u][i].first);
                    vis[v[u][i].first]=1;
                }
            }
    }
    for(int i=1;i<=n;++i)
        cout<<dis[i]<<' ';
    return 0;
}

2.DFS算法

由于题目保证是一颗树,所以任意两个点只有唯一一条路径,故我们也可以使用DFS求路径长度。
还是用邻接表建边,DFS每个点。
如果已经走到目的地了,直接输出当前答案即可(我当图做取了最小值)
如果没走到,则走到下一个点,将答案增加两人联络的代价。
由于是树所以可以不回溯(我当图做顺手回溯了只有\(\textcolor[RGB]{52,152,219}{TLE}80pts\)

DFS算法 80pts Code

#include<bits/stdc++.h>
#define N 1000007
#define INF 1e18
#define MOD 1000000007
#define LL long long
#define pb push_back
#define lb long double
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define IOS ios::sync_with_stdio(0),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
LL n,a[5005],minn=LONG_LONG_MAX;
bool vis[5005];//可以不用
vector<LL>v[5005];
void dfs(LL k,LL x,LL cnt)
{
    if(k==x)
    {
        minn=min(minn,cnt);
        return;
    }
    for(int i=0;i<v[k].size();++i)
        if(!vis[v[k][i]])
        {
            vis[v[k][i]]=1;
            dfs(v[k][i],x,cnt+a[v[k][i]]);
            vis[v[k][i]]=0;//这里回溯了所以超时
        }
}
int main()
{
    IOS;
    cin>>n;
    for(int i=1;i<=n;++i)
        cin>>a[i];
    for(int i=1,x,y;i<n;++i)
    {
        cin>>x>>y;
        v[x].pb(y);
        v[y].pb(x);
    }
    cout<<a[1]<<' ';
    for(int i=2;i<=n;++i)
    {
        memset(vis,0,sizeof(vis));
        minn=LONG_LONG_MAX;
        dfs(1,i,a[1]);
        cout<<minn<<' ';
    }
    return 0;
}

DFS算法 AC Code

#include<bits/stdc++.h>
#define N 1000007
#define INF 1e18
#define MOD 1000000007
#define LL long long
#define pb push_back
#define lb long double
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define IOS ios::sync_with_stdio(0),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
LL n,a[5005],minn=LONG_LONG_MAX;
vector<LL>v[5005];
bool vis[5005];
void dfs(LL k,LL x,LL cnt)
{
    if(minn<cnt)return;
    if(k==x)
    {
        minn=min(minn,cnt);
        return;
    }
    for(int i=0;i<v[k].size();++i)
        if(!vis[v[k][i]])
            vis[v[k][i]]=1,dfs(v[k][i],x,cnt+a[v[k][i]]);
}
int main()
{
    IOS;
    cin>>n;
    for(int i=1;i<=n;++i)
        cin>>a[i];
    for(int i=1,x,y;i<n;++i)
    {
        cin>>x>>y;
        v[x].pb(y);
        v[y].pb(x);
    }
    cout<<a[1]<<' ';
    for(int i=2;i<=n;++i)
    {
        memset(vis,0,sizeof(vis));
        vis[1]=1;
        minn=LONG_LONG_MAX;
        dfs(1,i,a[1]);
        cout<<minn<<' ';
    }
    return 0;
}
posted @ 2024-08-04 16:22  Firra3500  阅读(5)  评论(0编辑  收藏  举报