• P2853 [USACO06DEC]Cow Picnic S


    题目传送门

    一、题意分析

    二、bfs解法

    1、链式前向星

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 10010; //10000条边
    
    queue<int> q;
    bool st[N];     //走过了没
    int n;          //n个牧场
    int m;          //m条有向路连接
    int k;          //k只奶牛
    int a[N];       //记录第i个奶牛在a[i]这个牧场里
    int sum[N];     //记录每个结点被bfs遍历到的次数
    
    int ans;
    
    //链式前向星建图
    int idx, head[N];
    struct Edge {
        int to, next;
    } edge[N];
    
    int add(int from, int to) {
        edge[++idx].to = to;
        edge[idx].next = head[from];
        head[from] = idx;
    }
    
    int main() {
        //k:奶牛数,n:牧场数,m:路线数
        cin >> k >> n >> m;
        for (int i = 1; i <= k; i++) cin >> a[i];//读入奶牛在哪个牧场里
    
        for (int i = 1; i <= m; i++) {
            int x, y;
            cin >> x >> y;
            add(x, y);//读入m条路径,建图,x->y有一条边
        }
    
        //从每个奶牛所在的牧场出发
        for (int i = 1; i <= k; i++) {
            //清空状态标识
            memset(st, 0, sizeof(st));
            //将第i个奶牛所在的第a[i]个牧场放入队列
            q.push(a[i]);
            //标识这个牧场已使用过,防止走回头路
            st[a[i]] = true;
            //广度优先搜索
            while (!q.empty()) {
                int x = q.front();
                q.pop();
                //链式前向星找每一条邻接边
                for (int i = head[x]; i; i = edge[i].next) {
                    //目标结点
                    int to = edge[i].to;
                    if (!st[to]) {//如果目标结点未使用过
                        st[to] = true;//标识为已使用
                        q.push(to);   //入队列
                    }
                }
            }
            //记录每个结点被遍历到的次数
            for (int j = 1; j <= n; j++) sum[j] += st[j];
        }
        //如果n个结点中,存在遍历次数等于k的结点,就是表示k个奶牛都可以到达这个位置
        for (int i = 1; i <= n; i++)
            if (sum[i] == k) ans++;
        //输出结果
        printf("%d", ans);
        return 0;
    }
    

    2、邻接表

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 10010; //10000条边
    
    queue<int> q;
    bool st[N];         //走过了没
    int n;              //n个牧场
    int m;              //m条有向路连接
    int k;              //k只奶牛
    int a[N];           //记录第i个奶牛在a[i]这个牧场里
    int sum[N];         //记录每个结点被BFS遍历到的次数
    vector<int> p[N];   //邻接表
    int ans;
    
    int main() {
        //k:奶牛数,n:牧场数,m:路线数
        cin >> k >> n >> m;
        for (int i = 1; i <= k; i++) cin >> a[i];//读入奶牛在哪个牧场里
    
        for (int i = 1; i <= m; i++) {
            int x, y;
            cin >> x >> y;
            p[x].push_back(y);//读入m条路径,建图,x->y有一条边
        }
        //从每个奶牛所在的牧场出发
        for (int i = 1; i <= k; i++) {
            //清空状态标识
            memset(st, 0, sizeof(st));
    
            //将第i个奶牛所在的第a[i]个牧场放入队列
            q.push(a[i]);
            //标识这个牧场已使用过,防止走回头路
            st[a[i]] = true;
            //广度优先搜索
            while (!q.empty()) {
                int x = q.front();
                q.pop();
                //邻接表的遍历
                for (int to:p[x]) {
                    if (!st[to]) {//如果目标结点未使用过
                        st[to] = true;//标识为已使用
                        q.push(to);   //入队列
                    }
                }
            }
            //记录每个结点被遍历到的次数
            for (int j = 1; j <= n; j++) sum[j] += st[j];
        }
        //如果n个结点中,存在遍历次数等于k的结点,就是表示k个奶牛都可以到达这个位置
        for (int i = 1; i <= n; i++)
            if (sum[i] == k) ans++;
        //输出结果
        printf("%d", ans);
        return 0;
    }
    

    3、邻接矩阵

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 10010; //10000条边
    
    queue<int> q;
    
    bool st[N];         //走过了没
    int n;              //n个牧场
    int m;              //m条有向路连接
    int k;              //k只奶牛
    int a[N];           //记录第i个奶牛在a[i]这个牧场里
    int sum[N];         //记录每个结点被bfs遍历到的次数
    int g[N][N];        //邻接矩阵
    int ans;
    
    int main() {
        //k:奶牛数,n:牧场数,m:路线数
        cin >> k >> n >> m;
        for (int i = 1; i <= k; i++) cin >> a[i];//读入奶牛在哪个牧场里
        for (int i = 1; i <= m; i++) {
            int x, y;
            cin >> x >> y;
            g[x][y] = 1;//读入m条路径,建图,x->y有一条边
        }
        //从每个奶牛所在的牧场出发
        for (int i = 1; i <= k; i++) {
            //清空状态标识
            memset(st, 0, sizeof(st));
            //将第i个奶牛所在的第a[i]个牧场放入队列
            q.push(a[i]);
            //标识这个牧场已使用过,防止走回头路
            st[a[i]] = true;
            //广度优先搜索
            while (!q.empty()) {
                int x = q.front();
                q.pop();
                //邻接矩阵的遍历
                for (int i = 1; i <= n; i++)
                    if (g[x][i] && !st[i]) {
                        st[i] = true;//标识为已使用
                        q.push(i);   //入队列
                    }
            }
            //记录每个结点被遍历到的次数
            for (int j = 1; j <= n; j++) sum[j] += st[j];
        }
        //如果n个结点中,存在遍历次数等于k的结点,就是表示k个奶牛都可以到达这个位置
        for (int i = 1; i <= n; i++)
            if (sum[i] == k) ans++;
        //输出结果
        printf("%d", ans);
        return 0;
    }
    

    三、dfs解法

    1、链式前向星

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1010 * 1010;  //牧场数上限,这里不算上乘积,就会有3个WA点,
    // 原因很简单,装不下!!这是边的数量上限,要注意,邻接表没有这个问题,一定要区别好!
    
    int n;          //n个牧场
    int m;          //m条有向路连接
    int k;          //k只奶牛
    int ans;        //ans为最终答案
    int a[N];       //a数组存储牛的位置
    int sum[N];     //sum数组为每个点被遍历的次数
    bool st[N];     //st数组用来判断点是否已经被访问过
    
    //链式前向星建图
    int idx, head[N];
    struct Edge {
        int to, next;
    } edge[N];
    
    int add_edge(int from, int to) {
        edge[++idx].to = to;
        edge[idx].next = head[from];
        head[from] = idx;
    }
    
    //进行图的深度优先遍历
    void dfs(int x) {
        st[x] = true;
        sum[x]++;               //将这个点遍历的次数+1
        //枚举节点编号
        for (int i = head[x]; i; i = edge[i].next) {
            int v = edge[i].to;
            if (!st[v]) dfs(v);//就遍历i号节点
        }
    }
    
    int main() {
        cin >> k >> n >> m;
        for (int i = 1; i <= k; i++) cin >> a[i];//输入每只奶牛的顺序
    
        //使用链式前向星保存数据边
        for (int i = 1; i <= m; i++) {
            int x, y;
            cin >> x >> y;
            add_edge(x, y);
        }
    
        //对奶牛的位置进行枚举
        for (int i = 1; i <= k; i++) {
            memset(st, 0, sizeof st);
            dfs(a[i]);                          //从每一只奶牛的位置开始遍历
        }
    
        //统计答案,如果当前节点被访问的次数恰好为奶牛的只数
        for (int i = 1; i <= n; i++) if (sum[i] == k) ans++;
        //输出最后答案
        cout << ans << endl;
        return 0;
    }
    

    2、邻接表

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 1010;  //牧场数上限
    
    int n;          //n个牧场
    int m;          //m条有向路连接
    int k;          //k只奶牛
    int ans;        //ans为最终答案
    vector<int> p[N]; //p数组为邻接表
    int a[N];       //a数组存储牛的位置
    int sum[N];     //sum数组为每个点被遍历的次数
    bool st[N];     //st数组用来判断点是否已经被访问过
    
    //进行图的深度优先遍历
    void dfs(int x) {
        st[x] = true;           //将现在访问的点标记为已遍历,防止走回头路
        sum[x]++;               //将这个点遍历的次数+1
        //枚举节点编号
        for (int v:p[x])
            if (!st[v]) dfs(v);//就遍历i号节点
    }
    
    int main() {
        cin >> k >> n >> m;
        for (int i = 1; i <= k; i++) cin >> a[i];//输入每只奶牛的顺序
        //使用邻接表保存数据边
        for (int i = 1; i <= m; i++) {
            int u, v;
            cin >> u >> v;
            //连接两边(注意不是双向边,是单向边)
            p[u].push_back(v);
        }
        //对奶牛的位置进行枚举
        for (int i = 1; i <= k; i++) {
            dfs(a[i]);                          //从每一只奶牛的位置开始遍历
            memset(st, false, sizeof(st)); //记得每次遍历完都需要清空标记数组
        }
    
        //统计答案,如果当前节点被访问的次数恰好为奶牛的只数
        for (int i = 1; i <= n; i++)
            if (sum[i] == k) ++ans;
    
        //输出最后答案
        cout << ans << endl;
        return 0;
    }
    

    3、邻接矩阵

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1010;  //牧场数上限
    
    int n;          //n个牧场
    int m;          //m条有向路连接
    int k;          //k只奶牛
    int ans;        //ans为最终答案
    int g[N][N];    //g数组为邻接矩阵
    int a[N];       //a数组存储牛的位置
    int sum[N];     //sum数组为每个点被遍历的次数
    bool st[N];     //st数组用来判断点是否已经被访问过
    
    //进行图的深度优先遍历
    void dfs(int x) {
        st[x] = true;           //将现在访问的点标记为已遍历,防止走回头路
        sum[x]++;               //将这个点遍历的次数+1
        //枚举节点编号
        for (int i = 1; i <= n; i++)
            //如果当前节点没有被访问过并且与当前节点有边连接
            if (!st[i] && g[x][i]) dfs(i);//就遍历i号节点
    }
    
    int main() {
        cin >> k >> n >> m;
        for (int i = 1; i <= k; i++) cin >> a[i];//输入每只奶牛的顺序
    
        //使用邻接矩阵保存数据边
        for (int i = 1; i <= m; i++) {
            int u, v;
            cin >> u >> v;
            //连接两边(注意不是双向边,是单向边)
            g[u][v] = 1;
        }
        //对奶牛的位置进行枚举
        for (int i = 1; i <= k; i++) {
            dfs(a[i]);                          //从每一只奶牛的位置开始遍历
            memset(st, false, sizeof(st)); //记得每次遍历完都需要清空标记数组
        }
        //统计答案,如果当前节点被访问的次数恰好为奶牛的只数
        for (int i = 1; i <= n; i++)
            if (sum[i] == k) ++ans;
    
        //输出最后答案
        cout << ans << endl;
        return 0;//完美结束
    }
    
  • 相关阅读:
    弄清变量名字空间
    Perl中文编码的处理
    了解魔符的含义
    Log::Minimal 小型可定制的log模块
    Perl – 文件测试操作符
    在源代码中使用Unicode字符
    editplus乱码charset的奇怪问题
    ASP.NET程序中常用代码汇总(一)
    ASP.NET程序中常用代码汇总(三)
    ASP.NET程序中常用代码汇总(二)
  • 原文地址:https://www.cnblogs.com/littlehb/p/15137294.html
Copyright © 2020-2023  润新知