求图上每个点能到达的点的个数

Real Magic
给一个无向图,问每个点能到达的点的数量。
直接并查集维护连通块点数。

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <set>
#include <stack>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (long long i= a; i <= b; i++)
#define reps(i, a, b) for (long long i = a; i >= b; i--)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/gcd(a,b)
#define ls(node) tree[node].ls
#define rs(node) tree[node].rs
#define val(node) tree[node].val
#define sum(node) tree[node].sum
#define lazy(node) tree[node].lazy
#define lazy1(node) tree[node].lazy1
#define lazy2(node) tree[node].lazy2
#define tr(node) tree[node]
using namespace std;
const int N = 3e4+ 7;
const int M = 50+7;
const int inf=0x3f3f3f;
const int mods =571373;
typedef long long ll;
int in[N];
int num[N];
int k=0;
int n,m;
vector<int>G[N];
bitset<N>dp[N];
int par[N];
int number[N];
int find(int x)
{
    if(par[x]==x)
        return x;
    else
        return par[x]=find(par[x]);
}
void unite(int u,int v)
{
    int x=find(u),y=find(v);
    if(x==y)
        return ;
    par[x]=y;
    number[y]+=number[x];
}
void init()
{
    for(int i=1; i<=n; i++)
    {
        par[i]=i;
        number[i]=1;
    }
}
int main()
{
    int t;
    int cnt=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        rep(i,1,m)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            unite(u,v);
        }
        printf("Case #%d:\n",++cnt);
        rep(i,1,n)
        {
            printf("%d ",number[find(i)]-1);
        }
        puts("");
    }
    return 0;
}

可达性统计
这次是有向图,不能用并查集来写。可以很容易想到对于 ( u , v ) ( u 可 到 v ) , a n s u = ∑ a n s v (u,v)(u可到v),ans_u=\sum ans_v (u,v)(uv),ansu=ansv,
所以可以用拓扑排序,从后往前遍历,或者dfs跑几遍,理论上可以直接一维dp做,但是判重很麻烦,懒得写了,等什么时候想起来,看看一维dp能不能。这里用bitset,(麻了又是二进制 ),又是熟悉的01表示能不能到达,最后用count函数获得1的数量就行了。

拓扑

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <set>
#include <stack>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (long long i= a; i <= b; i++)
#define reps(i, a, b) for (long long i = a; i >= b; i--)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/gcd(a,b)
#define ls(node) tree[node].ls
#define rs(node) tree[node].rs
#define val(node) tree[node].val
#define sum(node) tree[node].sum
#define lazy(node) tree[node].lazy
#define lazy1(node) tree[node].lazy1
#define lazy2(node) tree[node].lazy2
#define tr(node) tree[node]
using namespace std;
const int N = 3e4+ 7;
const int M = 50+7;
const int inf=0x3f3f3f;
const int mods =571373;
typedef long long ll;
int in[N];
int num[N];
int k=0;
int n,m;
vector<int>G[N];
bitset<N>dp[N];
void topo()
{
    queue<int>q;
    for(int i=1; i<=n; i++)
        if(!in[i])
            q.push(i);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        num[++k]=u;
        for(int i=0; i<G[u].size(); i++)
        {
            int v=G[u][i];
            in[v]--;
            if(!in[v])
                q.push(v);
        }
    }
}
int par[N];
int number[N];
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,m)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        in[v]++;
    }
    topo();
    reps(i,n,1)
    {
        int u=num[i];
        dp[u][u]=1;
        for(int j=0; j<G[u].size(); j++)
        {
            int v=G[u][j];
            dp[u]|=dp[v];
        }
    }
    rep(i,1,n)
    {
        printf("%d\n",dp[i].count());
    }
    return 0;
}

dfs

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <set>
#include <stack>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (long long i= a; i <= b; i++)
#define reps(i, a, b) for (long long i = a; i >= b; i--)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/gcd(a,b)
#define ls(node) tree[node].ls
#define rs(node) tree[node].rs
#define val(node) tree[node].val
#define sum(node) tree[node].sum
#define lazy(node) tree[node].lazy
#define lazy1(node) tree[node].lazy1
#define lazy2(node) tree[node].lazy2
#define tr(node) tree[node]
using namespace std;
const int N = 3e4+ 7;
const int M = 50+7;
const int inf=0x3f3f3f;
const int mods =571373;
typedef long long ll;
const int INF = 0x3f;
int in[N];
int num[N];
int k=0;
int n,m;
vector<int>G[N];
bitset<N>dp[N];
void dfs(int u)
{
    dp[u][u]=1;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(dp[v].count()==0)dfs(v);//已经算过的就不用再算了,不然必t
        dp[u]|=dp[v];
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,m)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        in[v]++;
    }
    for(int i=1;i<=n;i++){
        if(in[i]==0)dfs(i);
    }
    rep(i,1,n)
    {
        printf("%d\n",dp[i].count());
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,让我来回答你的问题。关于使用C语言队列解m*n迷宫问题,通常采用广度优先搜索算法,其具体步骤如下: 1.定义一个结构体表示迷宫中的节点,包括节点的行、列、步数和从哪个节点到达该节点。 2.定义一个队列,用于存储待搜索的节点。 3.将起点加入队列,并将其步数设为0. 4.每次取出队头的节点,遍历其上下左右四个方向的节点,若该节点未被访问过且不是障碍物,则将其加入队列,并更新步数和父节点信息。 5.重复步骤4,直到队列为空。此时,所有可到达终点的路径已经被遍历过了。 6.输出从起点到终点的所有路径,以及路径的数量。 以下是C语言代码示例: ``` #include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 struct node { int x,y; //节点所在的行和列 int step; //起点到该节点的步数 int pre; //从哪个节点到达该节点 }que[MAXSIZE]; int n,m,endx,endy; //迷宫大小、终点坐标 int maze[MAXSIZE][MAXSIZE]; //迷宫地 int dx[4]={0,0,1,-1}; //用于计算四个方向相邻节点的行列坐标增量 int dy[4]={1,-1,0,0}; int vis[MAXSIZE][MAXSIZE]; //记录节点是否被访问过 int head=0,tail=0; //队头和队尾 void bfs() { int i; //将起点加入队列 que[tail].x=0; que[tail].y=0; que[tail].step=0; que[tail].pre=-1; tail++; vis[0][0]=1; while(head<tail) //队列不为空 { struct node p=que[head]; //取队头节点并出队 head++; if(p.x==endx && p.y==endy) //已到达终点 { int cnt=0; //记录可到达终点的路径数量 int path[MAXSIZE]={0}; //记录所有路径 //从终点一直查找父节点,直到到达起点 while(p.pre!=-1) { path[cnt++]=p.pre; p=que[path[cnt-1]]; } //反向输出路径 printf("Path %d: (%d,%d)",cnt,endx,endy); for(i=cnt-1;i>=0;i--) { p=que[path[i]]; printf(" -> (%d,%d)",p.x,p.y); } printf("\n"); } //遍历四个方向 for(i=0;i<4;i++) { int nx=p.x+dx[i]; int ny=p.y+dy[i]; if(nx>=0 && nx<n && ny>=0 && ny<m && !maze[nx][ny] && !vis[nx][ny]) //判断是否越界、是否是障碍物,是否已被访问过 { vis[nx][ny]=1; que[tail].x=nx; que[tail].y=ny; que[tail].step=p.step+1; que[tail].pre=head-1; tail++; //新节点入队 } } } } int main() { int i,j; printf("Input the size of the maze:\n"); scanf("%d %d",&n,&m); printf("Input the maze:\n"); for(i=0;i<n;i++) for(j=0;j<m;j++) scanf("%d",&maze[i][j]); printf("Input the coordinate of the end point:\n"); scanf("%d %d",&endx,&endy); bfs(); return 0; } ``` 以上就是使用C语言队列解m*n迷宫问题的代码,可以输出解的个数及每个解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值