第6章图论

A1003


#include<iostream>
#include<cstring>
using namespace std;

const int maxn=510;

int d[maxn][maxn],w[maxn];

int dist[maxn],cnt[maxn],sum[maxn];

int n,m,S,T;

bool st[maxn]={false};

void dijkstra()
{
    memset(dist, 0x3f, sizeof dist);      //对dist进行 初始化 为 0x3f

    dist[S]=0,cnt[S]=1,sum[S]=w[S];       //到起点S的最短距离是0 ,路径条数设置为1,同时到起点的 点权就是 w对应的点权

    for(int i=0; i<n; i++)
    {
        int t=-1;                                         //在dist中,找到 距离 最小的点 其实 t就是 中转点
        for(int j=0; j<n; j++)
        {
            if(st[j]==false && (t==-1 || dist[t]>dist[j]))
                t=j;
        }

        st[t]=true;           //对t进行 标记

        for(int j=0; j<n; j++)                    //遍历n个点
        {
            if(dist[j]>dist[t]+d[t][j])        //如果 t是 更小的点  更新 最短路径  和 最短路径的 条数 及 边权
            {
                dist[j]=dist[t]+d[t][j];
                cnt[j]=cnt[t];
                sum[j]=sum[t]+w[j];
            }
            else if(dist[j]==dist[t]+d[t][j])          //如果路径相同 直接加等于,然后 更新最大边权
            {
                cnt[j]+=cnt[t];
                sum[j]=max(sum[j],sum[t]+w[j]);
            }
        }

    }

}

int main()
{
    cin >> n >> m >> S >> T;

    for (int i = 0; i < n; i ++ ) cin >> w[i];      //w表示  点 权

    memset(d, 0x3f, sizeof d);       //将边权 也初始化为 0x3f
    while (m -- )
    {
        int a, b, c;
        cin >> a >> b >> c;
        d[a][b] = d[b][a] = c;       //因为是 无向图,设置为双向
    }

    dijkstra();

    cout << cnt[T] << ' ' << sum[T] << endl;

    return 0;
}

A1030



#include<iostream>
#include<cstring>
using namespace std;

const int maxn=510;

int d[maxn][maxn],w[maxn][maxn];

int pre[maxn];

int dist[maxn],sum[maxn];

bool st[maxn]={false};

int n,m,S,T;

void print(int x)
{
    if(x==S)
    {
        cout << S << " ";
        return ;
    }
    print(pre[x]);
    cout << x << " ";
}

void dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    memset(sum,0x3f,sizeof sum);
    dist[S]=0,sum[S]=0;
    for(int i=0; i<n; i++)
    {
        int t=-1;
        for(int j=0; j<n; j++)
        {
            if(st[j]==false && (t==-1 || dist[t]>dist[j]))
                t=j;
        }
        st[t]=true;

        for(int j=0; j<n; j++)
        {
            if(dist[j]>dist[t]+d[t][j])
            {
                dist[j]=dist[t]+d[t][j];
                sum[j]=sum[t]+w[t][j];
                pre[j]=t;
            }
            else if(dist[j]==dist[t]+d[t][j])
            {
                if(sum[j]>sum[t]+w[t][j])
                {
                    sum[j]=sum[t]+w[t][j];
                    pre[j]=t;
                }
            }
        }

    }

}

int main()
{
    cin >> n >> m >> S >> T;
    memset(d,0x3f,sizeof d);
    for(int i=0; i<m; i++)
    {
        int a,b,c,k;
        cin >> a >> b >> c >> k;
        d[a][b]=d[b][a]=c;
        w[a][b]=w[b][a]=k;
    }

    dijkstra();
    print(T);
    cout << dist[T] << " " << sum[T] << endl;

}

A1087


#include<iostream>
#include<unordered_map>
#include<cstring>
#include<vector>
using namespace std;

const int maxn=210;

int n,m,S,T;

unordered_map<string,int> mp;

int w[maxn],d[maxn][maxn],dist[maxn],cnt[maxn],cost[maxn],sum[maxn];   //最短路径条数 最短路径 点权值 路径上的个数

int pre[maxn];

bool st[maxn]={false};

void dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0,cnt[1]=1;

    for(int i=0; i<n; i++)           //这个for表示 n个节点 循环n-1次
    {
        int t=-1;
        for(int j=1; j<=n; j++)      //表示遍历每一个点的下标
        {
            if(st[j]==false && (t==-1 || dist[t]>dist[j]))
            {
                t=j;
            }
        }
        st[t]=true;

        for(int j=1; j<=n; j++)        //遍历n个点
        {
            if(dist[j]>dist[t]+d[t][j])
            {
                dist[j]=dist[t]+d[t][j];
                cnt[j]=cnt[t];
                cost[j]=cost[t]+w[j];
                sum[j]=sum[t]+1;
                pre[j]=t;
            }
            else if(dist[j]==dist[t]+d[t][j])
            {
                cnt[j]+=cnt[t];                   //路径相同直接 加 不需要任何 条件
                if(cost[j]<cost[t]+w[j])       //需要找到 最大的 幸福指数
                {
                    cost[j]=cost[t]+w[j];
                    sum[j]=sum[t]+1;
                    pre[j]=t;
                }
                else if(cost[j]==cost[t]+w[j])
                {
                    if(sum[j]>sum[t]+1)
                    {
                        sum[j]=sum[t]+1;
                        pre[j]=t;
                    }

                }
            }
        }


    }

}

int main()
{
    string city[maxn];
    cin >> n >> m >> city[1];
    mp[city[1]]=1;
    for(int i=2; i<=n; i++)
    {
        cin >> city[i] >> w[i];
        mp[city[i]]=i;
    }
    memset(d,0x3f,sizeof d);
    for(int i=0; i<m; i++)
    {
        string a,b;
        int c;
        cin >> a >> b >> c;
        int aa=mp[a],bb=mp[b];
        d[aa][bb]=d[bb][aa]=c;
    }

    T=mp["ROM"];
    dijkstra();

    cout << cnt[T] << " " << dist[T] << " " << cost[T] << " " << cost[T]/sum[T] << endl;

    vector<int> path;
    for(int i=T; i!=1; i=pre[i])
        path.push_back(i);

    cout << city[1];

    for(int i=path.size()-1; i>=0; i--)
    {
        cout << "->" << city[path[i]];
    }

    return 0;
}

A1122


#include <iostream>
#include <cstring>

using namespace std;

const int N = 210;

int n, m;
bool g[N][N], st[N];
int nodes[N * 2];

bool check(int cnt)
{
    if (nodes[0] != nodes[cnt - 1] || cnt != n + 1) return false;

    memset(st, 0, sizeof st);
    for (int i = 0; i < cnt - 1; i ++ )
    {
        st[nodes[i]] = true;
        if (g[nodes[i]][nodes[i + 1]]==false)
            return false;
    }

    for (int i = 1; i <= n; i ++ )
        if (st[i]==false)
            return false;

    return true;
}

int main()
{
    cin >> n >> m;
    while (m -- )
    {
        int a, b;
        cin >> a >> b;
        g[a][b] = g[b][a] = true;
    }

    int k;
    cin >> k;
    while (k -- )
    {
        int cnt;
        cin >> cnt;
        for (int i = 0; i < cnt; i ++ ) cin >> nodes[i];

        if (check(cnt)) puts("YES");
        else puts("NO");
    }

    return 0;
}

A1126



#include<iostream>
using namespace std;

/*
        欧拉回路:1.连通   2.偶度数点的个数为n 
        
        半欧拉回路:1.连通 2.奇度数的点的个数为2  偶度数点的个数为n-2
        
        剩下情况,不是欧拉回路

*/

const int maxn=510;

bool st[maxn],g[maxn][maxn];

int n,m,d[maxn];

int dfs(int x)         //通过dfs来判断 是否是 联通图
{
    st[x]=true;
    int res=1;

    for(int i=1; i<=n; i++)
    {
        if(st[i]==false && g[x][i]==true)
            res+=dfs(i);
    }

    return res;

}

int main()
{
    cin >> n >> m;
    while(m--)
    {
        int a,b;
        cin >> a >> b;
        g[a][b]=g[b][a]=true;
        d[a]++,d[b]++;
    }

    for(int i=1; i<=n; i++)
    {
        if(i!=1)
            cout << " ";
        cout << d[i];
    }

    cout << endl;

    if(dfs(1)==n)    //判断该 图是否为联通的
    {
        int res=0;
        for(int i=1; i<=n; i++)
        {
            if(d[i]%2==0)
                res++;
        }
        if(res==n)
            cout << "Eulerian" << endl;
        else if(res+2==n)
            cout << "Semi-Eulerian" << endl;
        else
            cout << "Non-Eulerian" << endl;
    }
    else
    {
        cout << "Non-Eulerian" << endl;
    }
    return 0;
}

A1131(优化版)

在这里插入图片描述



/*
    这道题首先 要找到 最小的站点停靠数量+最少的换乘次数
    
    对应的话 就是 最短路径+最少的交叉路口
    
    
    这道题基本上也就是 Dijkstra优化版本 模板
*/

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

const int maxn=1000010;

int n,idx;

int stop[maxn];

int e[maxn],w[maxn],line[maxn],h[maxn],ne[maxn],dist[maxn],cnt[maxn],pre[maxn];

string Info[maxn];

bool st[maxn];

typedef pair<int,int> PII;


void add(int a,int b,int c,int d)                       //add(stop[j],stop[k],len,T)
{
    e[idx]=b,w[idx]=c,line[idx]=d,ne[idx]=h[a],h[a]=idx++;          //e[i]表示下一个 节点,w表示从起点到idx的权值,line表示idx这个点是哪条线
}

string getNum(int x)
{
    char res[5];
    sprintf(res,"%04d",x);
    return res;
}

void dijkstra(int start,int end)
{
    memset(dist,0x3f,sizeof dist);
    memset(cnt,0x3f,sizeof cnt);
    memset(st,false,sizeof st);

    dist[start]=cnt[start]=0;

    priority_queue<PII,vector<PII>,greater<PII>> heap;         //小根堆

    heap.push({0,start});

    while(!heap.empty())
    {
        auto t=heap.top();
        heap.pop();

        int vers=t.second;

        if(vers==end)
            break;

        if(st[vers])
            continue;

        st[vers]=true;

        for(int i=h[vers]; i!=-1; i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[vers]+w[i])     //最短路径
            {
                dist[j]=dist[vers]+w[i];
                cnt[j]=cnt[vers]+1;
                pre[j]=vers;
                Info[j]="Take Line#" + to_string(line[i])  + " from " + getNum(vers) + " to " + getNum(j) + ".";
                heap.push({dist[j],j});
            }
            else if(dist[j]==dist[vers]+w[i])
            {
                if(cnt[j]>cnt[vers]+1)      //通过 最少的 点数
                {
                    cnt[j]=cnt[vers]+1;
                    pre[j]=vers;
                    Info[j]="Take Line#" + to_string(line[i])  + " from " + getNum(vers) + " to " + getNum(j) + ".";
                }
            }
        }


    }

    cout << dist[end] << endl;

    vector<string> path;

    for(int i=end; i!=start; i=pre[i])
    {
        path.push_back(Info[i]);
    }

    for(int i=path.size()-1; i>=0; i--)
    {
        cout << path[i] << endl;
    }

}


int main()
{
    cin >> n;               //输入n个点
    int m;                  //m条边
    memset(h,-1,sizeof(h));      //对h初始化为-1

    for(int T=1; T<=n; T++)
    {
        cin >> m;                   //输入站的个数
        for(int i=0; i<m; i++)
        {
            cin >> stop[i];
        }

        for(int j=0; j<m; j++)     //将所有的点连接成一条边
        {
            for(int k=0; k<j; k++)
            {
                int len;
                if(stop[0]!=stop[m-1])   //如果 这条 不是 一条环路
                    len=j-k;
                else                    //如果这条线 是一条 环路
                {   
                    len=min(j-k,k+m-1-j);
                }

                add(stop[j],stop[k],len,T);
                add(stop[k],stop[j],len,T);
            }
        }
    }

    int k;
    cin >> k;
    int start,end;
    while(k--)
    {
        cin >> start >> end;
        dijkstra(start,end);
    }
}

A1134


#include<iostream>
#include<cstring>
using namespace std;

const int maxn=10100;

int n,m;

/*
    题目的思路是通过点来观察,边是否都存在;解题思路是通过 遍历每一条边来观察 该条边上的 两个点是否存在
*/

struct node
{
    int a,b;
}Node[maxn];

bool st[maxn];

int main()
{
     cin >> n >> m;
     for(int i=0; i<m; i++)
     {
         cin >> Node[i].a >> Node[i].b;
     }

     int k;
     cin >> k;
     while(k--)
     {
         int cnt;
         cin >> cnt;

         memset(st,false,sizeof st);
         for(int i=0; i<cnt; i++)
         {
             int temp;
             cin >> temp;
             st[temp]=true;
         }

         int i;
         for(i=0; i<m; i++)
         {
             if(st[Node[i].a]==false && st[Node[i].b]==false)
                break;
         }

         if(i==m)
         {
             cout << "Yes" << endl;
         }
         else
            cout << "No" << endl;

     }
     return 0;
}

A1142



#include<iostream>
using namespace std;

const int maxn=310;

int n,m;

int g[maxn][maxn];

int vers[maxn];

bool isClique(int cnt)
{
    for(int i=0; i<cnt; i++)
        for(int j=0; j<i; j++)
        {
            if(g[vers[i]][vers[j]]==false)
                return false;
        }
    return true;
}

bool isMaximal(int cnt)
{
    bool st[maxn]={false};

    for(int i=0; i<cnt; i++)
        st[vers[i]]=true;

    for(int i=1; i<=n; i++)
    {
        bool success=true;
        if(st[i]==false)
        {
            for(int j=0; j<cnt; j++)
            {
                if(g[i][vers[j]]==false)
                {
                    success=false;
                    break;
                }
            }
            if(success)
            {
                return false;
            }
        }
    }

    return true;

}

int main()
{
    cin >> n >> m;
    for(int i=0; i<m; i++)
    {
        int a,b;
        cin >> a >> b;
        g[a][b]=g[b][a]=true;
    }

    int k;
    cin >> k;
    for(int i=0; i<k; i++)
    {
        int cnt;
        cin >> cnt;
        for(int j=0; j<cnt; j++)
        {
            cin >> vers[j];

        }

        if(isClique(cnt))
        {
            if(isMaximal(cnt))
            {
                cout << "Yes" << endl;
            }
            else
                cout << "Not Maximal" << endl;
        }
        else
            cout << "Not a Clique" << endl;
    }
}

A1146



#include<iostream>
using namespace std;

const int maxn=10010;

struct node
{
    int a,b;
}Node[maxn];

int n,m;

int main()
{
    cin >> n >> m;
    for(int i=0; i<m; i++)
    {
        cin >> Node[i].a >> Node[i].b;
    }
    int k;
    cin >> k;
    int inq=1;
    for(int i=0; i<k; i++)
    {
        int vers[maxn];
        bool success=true;
        for(int j=1; j<=n; j++)
        {
            int temp;
            cin >> temp;
            vers[temp]=j;
        }

        for(int i=0; i<m; i++)
        {
            if(vers[Node[i].a]>vers[Node[i].b])
            {
                success=false;
                break;
            }
        }

        if(success==false)
        {
            if(inq!=1)
                cout << " ";
            cout << i;
            inq++;
        }

    }
    return 0;
}

A1150


/*
    这道题就是统计两个点之间的距离
    
    不是环路                                                简单环路                                             环路
    1.有的点没有访问                                   访问的点数为n+1                 访问点数不是n+1
    2.两个点之间没有路径

*/

#include<iostream>
#include<cstring>
using namespace std;

const int maxn=222;
const int INF=0x3f3f3f3f;

int G[maxn][maxn];

int n,m,k;

int main()
{
    fill(G[0],G[0]+maxn*maxn,INF);        //对G进行初始化
    cin >> n >> m;
    int temp1,temp2,temp3;
    
    for(int i=0; i<m; i++)
    {
        cin >> temp1 >> temp2 >> temp3;
        G[temp1][temp2]=G[temp2][temp1]=temp3;
    }
    
    cin >> k;
    int temp4;
    int min_dis=INF,min_id;
    
    for(int T=1; T<=k; T++)
    {
        int vers[maxn];
        bool st[maxn]={false},success=true;
        
        int sum=0;
        cin >> temp4;
        
        for(int i=0; i<temp4; i++)
        {
            cin >> vers[i];
            st[vers[i]]=true;
        }
        
        for(int j=0; j+1<temp4; j++)
        {
            int a=vers[j],b=vers[j+1];
            if(G[a][b]==INF)        //如果两个点之间没有路,说明不是一个环路
            {
                sum=-1;
                break;
            }
            else
            {
                sum+=G[a][b];     //否则统计 两个 点 之间的 距离 
            }
        }

        if(vers[0]!=vers[temp4-1])   //始终点不一样,不是一个环路
            success=false;

        for(int k=1; k<=n; k++)       //有的点没有访问到
        {
            if(st[k]==false)
            {
                 success=false;
                 break;
            }
        }

        if(sum==-1)
        {
            printf("Path %d: NA (Not a TS cycle)\n",T);
        }
        else
        {
            if(success==false)
            {
                printf("Path %d: %d (Not a TS cycle)\n",T,sum);
            }
            else
            {
                if(temp4==n+1)
                {
                    printf("Path %d: %d (TS simple cycle)\n",T,sum);
                }
                else
                {
                    printf("Path %d: %d (TS cycle)\n",T,sum);
                }
                
                if(min_dis>sum)
                {
                    min_dis=sum;
                    min_id=T;
                }                
            }


        }


    }
    printf("Shortest Dist(%d) = %d\n",min_id,min_dis);
    return 0;
}

A1154



#include<iostream>
#include<set>
using namespace std;

const int maxn=10111;

int n,m;

struct node
{
    int a,b;
}Node[maxn];

int main()
{
    cin >> n >> m;
    for(int i=0; i<m; i++)
    {
        cin >> Node[i].a >> Node[i].b;
    }

    int k;
    cin >> k;
    while(k--)
    {
        set<int> color;
        int color1[maxn];
        bool st[maxn]={false};
        bool success=true;
        int res=0;
        for(int i=0; i<n; i++)
        {
            int temp;
            cin >> temp;
            color.insert(temp);
            color1[i]=temp;
        }

        for(int i=0; i<m; i++)
        {
            if(color1[Node[i].a]==color1[Node[i].b])
            {
                cout << "No" << endl;
                success=false;
                break;
            }
        }

        if(success)
            cout << color.size() << "-coloring" << endl;

    }
    return 0;
}

A1018

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 510, INF = 0x3f3f3f3f;

int C, n, S, m;
int c[N];
int g[N][N];
int dist[N];
bool st[N];

vector<int> path, ans;
int send = INF, bring = INF;

void dijkstra()           //相当于将dist最短路径铺好
{
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;

    for (int i = 0; i < n; i ++ )
    {
        int t = -1;
        for (int j = 0; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[j] < dist[t]))
                t = j;

        st[t] = true;
        for (int j = 0; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);
    }
}

//s表示当前 需要 带去 多少量 自行车?
void dfs(int u, int s, int mins)    //当前走到u,当前总和是s,当前最小值是mins

{
    if (u)      //除了起点之外,对s和mins进行更新
    {
        s -= (C + 1) / 2 - c[u];        //这个s就是 根据 每一条路径  计算出来  到达下一个站点的值
        mins = min(mins, s);          //mins就是不断统计 s最小值,表示需要自行车最多的那种情况,最终这个mins表示的就是从PBMS中 运过来的 自行车的 数量
    }

    if (u == S)         //刚好走完 最短路径中 的 其中 一条时,来判断一下他的值
    {
        int sd = abs(min(mins, 0));      //mins小于0,表示需要带mins辆车,如果mins》0,表示带0辆车
        int bg = s + sd;

        if (sd < send) ans = path, send = sd, bring = bg;          //需要找到最小的send和bring的值,其中sd和bg都是临时的
        else if (sd == send && bg < bring) ans = path, bring = bg;

        return;
    }

    for (int i = 1; i <= n; i ++ )             //遍历一下从u出发的所有边
        if (dist[u] == g[u][i] + dist[i])       //必须是在最短路径中,所以才会有这个if判断
        {
            path.push_back(i);    
            dfs(i, s, mins);
            path.pop_back();
        }
}

int main()
{
    cin >> C >> n >> S >> m;
    for (int i = 1; i <= n; i ++ ) cin >> c[i];          //c表示每个 站点 自行车的 情况 

    memset(g, 0x3f, sizeof g);           //将g调整为最大值
    
    for (int i = 0; i < m; i ++ )
    {
        int x, y, z;
        cin >> x >> y >> z;
        g[x][y] = g[y][x] = z;
    }

    dijkstra();

    path.push_back(0);   
    dfs(0, 0, 0);                //从起点出发,最开始一辆自行车都不带,中间最小值为0

    cout << send << ' ' << 0;            //send表示带去的数量 
    for (int i = 1; i < ans.size(); i ++ )      //ans存放最后的路径
        cout << "->" << ans[i];
    cout << " " << bring << endl;           //bring存放 带回去的自行车数量

    return 0;
}

A1072

在这里插入图片描述



/*
    给出加油站和居民区的 距离,选择一个合适的加油站,满足一下条件:
    1.要求所选加油站尽可能 远离 居民区,所以 必须 满足  距离 该 加油站最近的  居民区 距离 最远
    2.要求 所有的 居民区 都在 范围之内 
    3.该加油站 到达  所有的  居民区 的  距离 最小
    
    如果 上面 条件 都 相同,则需要 输出  最小的 加油站 编号

*/

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1020, INF = 0x3f3f3f3f;

int n, m, k, D;
int g[N][N];
int dist[N];
bool st[N];

int get(string s)              //将所有的加油站的编号设置为 n+1
{
    if (s[0] == 'G') return n + stoi(s.substr(1));
    return stoi(s);
}

void dijkstra(int start, int &mind, int &sumd)
{
    memset(dist, 0x3f, sizeof dist);
    memset(st, 0, sizeof st);

    dist[start] = 0;
    for (int i = 0; i < n + m; i ++ )
    {
        int t = -1;
        for (int j = 1; j <= n + m; j ++ )
            if (!st[j] && (t == -1 || dist[j] < dist[t]))
                t = j;

        st[t] = true;

        for (int j = 1; j <= n + m; j ++ )        //从 每个 加油站 出发,求出 他 所能 到达 的 最小距离 
            dist[j] = min(dist[j], dist[t] + g[t][j]);
    }

    for (int i = 1; i <= n; i ++ )
        if (dist[i] > D)          //如果 距离 超出了 范围D 则 设置mind为-INF
        {
            mind = -INF;
            return;
        }

    mind = INF, sumd = 0;
    for (int i = 1; i <= n; i ++ )        //遍历 n个 居民区
    {
        mind = min(mind, dist[i]);       //前面 这个 值,必须 找到mind的最小值
        sumd += dist[i];
    }
}

int main()
{
    cin >> n >> m >> k >> D;

    memset(g, 0x3f, sizeof g);
    while (k -- )
    {
        string a, b;
        int z;
        cin >> a >> b >> z;
        int x = get(a), y = get(b);

        g[x][y] = g[y][x] =z;
    }
    
    //最后输出的是 加油站 到达 居民区的 和的平均距离

    int res = -1, mind = 0, sumd = INF;         //res表示合适加油站的编号,mind表示距离加油站最近的最大距离,sumd表示该加油站到达 所有 局民区 的总的距离
    
    for (int i = n + 1; i <= n + m; i ++ )           //遍历m个加油站
    {
        int d1, d2;
        dijkstra(i, d1, d2);              //从每个 加油站 出发

        if (d1 > mind) res = i, mind = d1, sumd = d2;          //这里 需要的是  最大 的 mind,如果 超出了 范围,则直接 mind=-INF,所以 当INF为  负的INF时,自然不用 理会
        else if (d1 == mind && d2 < sumd) res = i, sumd = d2;
    }

    if (res == -1) puts("No Solution");
    else printf("G%d\n%.1lf %.1lf\n", res - n, (double)mind, (double)sumd / n);

    return 0;
}


A1076

在这里插入图片描述


#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

const int N = 1010, M = 100010;           //n的值 小于等于1000  每个点后面的个数小于等于100   所以最多有10^6条边

int n, m;
int h[N], e[M], ne[M], idx;        //邻接表 来 存储 数据      e和ne都根 边 有关
bool st[N];

void add(int a, int b)          //模板函数
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

int bfs(int start)            //宽搜
{
    queue<int> q;
    memset(st, 0, sizeof st);    //有k次询问,然后 每次将 st的值 设置为 false

    q.push(start);
    st[start] = true;    //将 起点 进行 一个 标记

    int res = 0;
    for (int step = 0; step < m; step ++ )
    {
        int sz = q.size();          //表示 每层 有多少个 点
        res += sz;

        for (int i = 0; i < sz; i ++ )     //需要 遍历 该层中的  每一个值
        {
            int t = q.front();
            q.pop();

            for (int j = h[t]; j!=-1; j = ne[j])
            {
                int k = e[j];
                if (!st[k])
                {
                    st[k] = true;
                    q.push(k);
                }
            }
        }
    }

    return res + q.size() - 1;      //  按照 题目 意思 比如 统计 前3层,实际上的  代码 统计 0,1,2层,需要统计的是1,2,3,q.size表示一层的人数,减1,其实表示第0层的一次 
}

int main()
{
    scanf("%d%d", &n, &m);

    memset(h, -1, sizeof h);
    for (int i = 1; i <= n; i ++ )
    {
        int cnt;
        scanf("%d", &cnt);
        while (cnt -- )
        {
            int x;
            scanf("%d", &x);
            add(x, i);        //x是i的粉丝,添加一条从x到i的距离
        }
    }

    int k;
    scanf("%d", &k);
    while (k -- )
    {
        int x;
        scanf("%d", &x);
        printf("%d\n", bfs(x));
    }

    return 0;
}

A1021

#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

/*
    这个题的思路就是 通过 
    1.并查集 求出 联通块数
    2.用邻接表存储数据,然后通过遍历 每个点,求出最大深度,就势将i存储起来

*/

const int N = 10010, M = N * 2;

int n;
int h[N], e[M], ne[M], idx;
int p[N];

int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

int dfs(int u, int father)         //u表示 对应的 节点 father表示根
{
    int depth = 0;
    for (int i = h[u]; ~i; i = ne[i])
    { 
        int j = e[i];          //j就是i的子节点
        if (j == father) continue;      //表示走了 回头路
        depth = max(depth, dfs(j, u) + 1);
    }
    return depth;
}

int main()
{
    cin >> n;

    memset(h, -1, sizeof h);
    for (int i = 1; i <= n; i ++ ) p[i] = i;

    int k = n;
    for (int i = 0; i < n - 1; i ++ )
    {
        int a, b;
        cin >> a >> b;
        if (find(a) != find(b))
        {
            k -- ;
            p[find(a)] = find(b);
        }
        add(a, b), add(b, a);
    }

    if (k > 1) printf("Error: %d components", k);
    else
    {
        vector<int> nodes;
        int max_depth = -1;

        for (int i = 1; i <= n; i ++ )
        {
            int depth = dfs(i, -1);                   //从第i个节点 向下 搜索
            if (depth > max_depth)
            {
                max_depth = depth;
                nodes.clear();
                nodes.push_back(i);
            }
            else if (depth == max_depth)
                nodes.push_back(i);
        }

        for (auto v : nodes) cout << v << endl;
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值