搜索与图论

#搜索与图论

  • 首先花费了好长时间才弄明白,邻接表的储存原理。这个笔记上有。

  • 第二就树的重心这个题,也是花费将近一个小时才弄明白。

  • 还有就是链表的范围至少是数据范围的俩倍,否则就会越界。产生错误答案,这题就遇到了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 10;
    int h[N] , e[N] , ne[N] ,idx ,ans = N ,n;
    bool st[N];//用于记录状态
    void add (int a , int b)
    {
        e[idx] = b , ne[idx] = h[a] , h[a] = idx ++;
    }//给 a,b 之间添加一条边。
    
    int dfs (int u)
    {
        st[u] = true;
        int size_ = 0 , sum = 0;
        for (int i = h[u] ; i != -1 ; i = ne[i])
        {
            int j = e[i];
            if (st[j]) continue;
    
            int s = dfs(j);
            size_ = max (s , size_);
            sum += s;
        }
        size_ = max (n - sum - 1 , size_);n 是所有结点的个数,sum 是某一棵子树的大小,-1 是因为是以这个点作为了重心。
        ans = min (ans , size_);
        //cout<<ans<<' '<<size_<<endl;
        return sum + 1;//返回sum + 1 是因为当sum = 0 时,此时至少还有一个结点。
    }
    int main()
    {
        cin>>n;
        memset(h , -1 , sizeof h);
        for (int i = 0 ; i < n - 1 ; i ++)
        {
            int a ,b;
            cin>>a>>b;
            add(a ,b) , add(b , a);
        }
        //cout<<"------"<<endl;
        dfs(1);
        cout<<ans;
        return 0;
    }
    
    • 图的宽度优先遍历
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 10 ;
    int e[N * 2] , ne[N * 2] , h[N] ,idx , n ,m , d[N];
    queue<int>q;
    void add (int a ,int b)
    {
        e[idx] = b , ne[idx] = h[a] , h[a] = idx ++;
    }
    void bfs ()
    {
        q.push(1);
        d[1] = 0;
        while (q.size())
        {
            int t = q.front();
            q.pop();
            for (int i = h[t] ; i != -1 ; i = ne[i])
            {
                int j = e[i];
                if (d[j] == -1){
                    q.push(j);
                    d[j] = d[t] + 1;
                }
    
                if (j == n){
                    cout<<d[j]<<endl;
                    return ;
                }
            }
        }
    
        cout<<-1<<endl;
    }
    int main()
    {
        cin>>n>>m;
        memset (d , -1 , sizeof d);
        memset (h , - 1 , sizeof h);
        for (int i = 0 ; i < m ; i ++)
        {
            int a , b;
            cin>>a>>b;
            add(a , b);
        }
        bfs();
        return 0;
    }

拓扑排序

首先说明几个图论里的几个概念,

入度:指向自己的边数

出度:指向别人的边数

一个拓扑图一定是一个有向无环图,有环的话,不能构成拓扑序列。

入度为零的点一定排在最前面的点,因为没有边指向它,所以说它就是起点。

拓扑排序的基本思想就是让所有入度为0的点都放在最前面,因为他们一定是起点,然后遍历每一个入度为0点指向的边,如果说,遍历到的这条边,我们就把这条边删去也就是指向的点的入度减1,当他入度为0时,那个他也就成为一个起点。

  • 这里还必须说一下,用数组来模拟队列,确实有不一样的好处,那就是数据还保存着。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int h[N] , e[N * 2] , ne[N * 2] , idx , d[N] ,n ,m;//d[N] 表示度数
int q[N];
void add (int a , int b)
{
   e[idx] = b , ne[idx] = h[a] , h[a] = idx ++;
}
bool tuoposort ()
{
   int hh = 0 , tt = -1;
   for (int i = 1 ; i <= n ; i ++){
       if (d[i] == 0) {
           q[ ++tt] = i;
       }
   }
   //cout<<tt<<"-"<<endl;
   while (hh <= tt)
   {
       int t = q[hh ++];
       for (int i = h[t] ; i != -1 ; i = ne[i]){
           int j = e[i];
           d[j] --;
           if (d[j] == 0)  q[ ++tt] = j;
       }
   }
   //cout<<tt<<endl;
   return tt == n - 1;
}
int main()
{
   cin>>n>>m;
   memset (h , -1 ,sizeof h);
   for (int i = 0 ; i < m ; i ++)
   {
       int a , b;
       cin>>a>>b;
       add(a ,b);
       d[b] ++;
   }
   //cout<<"------"<<endl;
   if (tuoposort())
   {
       for (int i = 0 ; i < n ; i ++) cout<<q[i]<<' ';
   }
   else puts("-1");

   return 0;
}

朴素版的迪杰斯特拉算法

具体思路纸质笔记上有。

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int g[N][N] , n ,m ,dist[N];
bool st[N];
int dijkstra (int n)
{
    //cout<<n<<endl;
    memset (dist , 0x3f3f3f , sizeof dist);
    dist[1] = 0 ;
    for (int i = 0 ; i < n ; i ++)
    {
        int t = -1 ;
        for (int j = 1 ; j <= n ; j ++){
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        }
        //cout<<t<<' '<<dist[t]<<endl;
        st[t] = true;

        for (int j = 1 ; j <= n ; j ++)
            dist[j] = min (dist[j] , dist[t] + g[t][j]);
    }
    if (dist[n] == 0x3f3f3f3f) return -1;
    else return dist[n];
}
int main()
{
    int n , m;
    cin>>n>>m;
    memset (g , 0x3f3f3f , sizeof g);
    while (m --)
    {
        int x , y , z;
        cin>>x>>y>>z;
        g[x][y] = min (g[x][y] , z);
    }
    cout<<dijkstra(n)<<endl;
    return 0;
}

堆优化版的迪杰斯特拉算法

#include<bits/stdc++.h>
using namespace std;
const int N = 300010;
int h[N] , e[N] , ne[N] ,w[N] ,idx ,dist[N];
bool st[N];
typedef pair<int,int>PII;
void add (int a , int b , int c)
{
    e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx ++;
}
int dijkstra (int n)
{
    //cout<<n<<"-----------"<<endl;
    memset (dist , 0x3f3f3f3f , sizeof dist);
    priority_queue<PII , vector<PII> ,greater<PII> > heap;
    dist[1] = 0;
    heap.push({0,1});
    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();
        int distance = t.first , ver = t.second;
        //cout<<ver<<' '<<distance<<endl;
        if (st[ver]) continue;
        st[ver] = true;
        for (int i = h[ver] ; i != -1 ; i = ne[i])
        {
            int j = e[i];
            if (distance + w[i] < dist[j]){
                    dist[j] = distance + w[i];
                heap.push({dist[j] ,j });
            }
        }
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    else return dist[n];
}
int main()
{
    int n , m;
    cin>>n>>m;
    memset(h , -1 , sizeof h);
    while (m --)
    {
        int x , y , z;
        cin>>x>>y>>z;
        add(x , y ,z);
    }
    cout<<dijkstra(n)<<endl;
    return 0;
}

floyd算法求多源最短路

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int g[N][N] ;
int n ,m ,k;
void floyd ()
{
    for (int k = 1 ; k <= n ; k ++)
    {
        for (int i = 1 ; i <= n ; i ++)
        {
            for (int j = 1 ; j <= n ; j ++)
            {
                g[i][j] = min (g[i][j] , g[i][k] + g[k][j]);
            }
        }
    }

}
int main()
{
    cin>>n>>m>>k;
    for (int i = 1 ; i <= n ; i ++)
    {
        for (int j = 1 ; j <= n ; j ++)
        {
            if (i == j) g[i][j] = 0;
            else g[i][j] = 1e9;
        }
    }
    while (m --)
    {
        int x , y ,z ;
        cin>>x>>y>>z;
        g[x][y] = min(g[x][y] , z);
    }

    floyd();

    while (k --)
    {
        int x , y;
        cin>>x>>y;
        if (g[x][y] > 1e9 / 2) cout<<"impossible"<<endl;
        else cout<<g[x][y]<<endl;
    }
    return 0;
}

bellman_ford算法

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
struct Edge
{
    int a ,b ,w;
}edges[100010];
int backup[N] , dist[N];
int n ,m ,k;
int bellman_ford ()
{
    memset (dist , 0x3f , sizeof dist);
    dist[1] = 0;

    for (int i = 0 ; i < k ; i ++)
    {
        memcpy (backup , dist , sizeof dist);
        for (int j = 0 ; j < m ; j ++)
        {
            int a = edges[j].a , b = edges[j].b , c = edges[j].w;
            dist[b] = min (dist[b] , backup[a] + c);
         }
    }

    if (dist[n] > 0x3f3f3f3f / 2) return -1;
    else return dist[n];
}
int main()
{
    cin>>n>>m>>k;
    for (int i = 0 ; i < m ; i ++)
    {
        cin>>edges[i].a>>edges[i].b>>edges[i].w;
    }
    if (bellman_ford() == -1) cout<<"impossible";
    else cout<<dist[n];
    return 0;
}

spfa求最短路

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int idx , n , m;
int h[N] , e[N] ,w[N] , ne[N] ,dist[N];
void add (int a , int b , int c)
{
    e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx ++;
}
queue<int>q;
bool st[N];
int spfa ()
{
    memset (dist , 0x3f3f3f3f ,sizeof dist);
    dist[1] = 0;
    q.push(1);
    st[1] = true;
    while (q.size())
    {
        int t = q.front();
        q.pop();
        st[t] = false;
        for (int i = h[t] ; i != -1 ; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                if (!st[j]){
                    st[j] = true;
                    q.push(j);
                }
            }
        }
    }

    if (dist[n] > 0x3f3f3f3f / 2) return -1;
    else return dist[n] ;
}
int main()
{
    cin>>n>>m;
    memset (h , -1 , sizeof h);
    while (m --)
    {
        int x ,y ,z;
        cin>>x>>y>>z;
        add(x , y ,z);
    }
    if (spfa() == -1) cout<<"impossible";
    else cout<<dist[n];
    return 0;
}

spfa判负环

#include<bits/stdc++.h>
using namespace std;
const int N = 2010 , M = 10010;
int h[N] ,ne[M] ,e[M] ,w[M] ,dist[N] , cnt[N];
int idx , n , m;
void add (int a , int b , int c)
{
    e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx ++;
}
queue<int>q;
bool st[N];
bool spfa ()
{
    memset (dist , 0x3f , sizeof dist);
    dist[1] = 0;
    for (int i = 1 ; i <= n ; i ++)
    {
        st[i] = true;
        q.push(i);
    }

    while (q.size())
    {
        int t = q.front();
        q.pop();
        st[t] = false;
        for (int i = h[t] ; i != -1 ; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                cnt[j] = cnt[t] + 1;
                if (cnt[j] > n) return true;
                if (!st[j])
                {
                    st[j] = true;
                    q.push(j);
                }
            }
        }
    }

    return false;
}
int main()
{
    cin>>n>>m;
    memset (h , -1 , sizeof h);
    while (m --)
    {
        int x , y , z;
        cin>>x>>y>>z;
        add(x , y , z);
    }
    if (spfa()) puts("Yes");
    else puts("No");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

觅你风川间!!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值