SP4882 DAGCNT2 - Counting in a DAG

Posted notscience

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SP4882 DAGCNT2 - Counting in a DAG相关的知识,希望对你有一定的参考价值。

题意:统计DAG上每一个点可以到达的所有节点的权值和(包括自己)。

思路如下:根据题意可以得到这样的关系:设(rec(x))(x)点可达点的集合,假设存在一条有向边((x,y)),有(rec(x)=rec(x)cup rec(y))。显然集合(rec(x))的初始状态为({x})(可以抵达自己)。那么反向建图之后作一个拓扑排序,根据这个式子去作统计即可。

反向建图并且做拓扑排序是为了保证无后效性。

当然还有一个问题:我们如何记录这个集合?
这个时候我们可以运用STL的bitset来完成这个任务。

bitset的一点点基础使用方法:
bitset的每一位只有(01)一个值,空间占用非常低(低于布尔类型),它支持随机访问,像(f[1])这样子可以直接访问其中的一个位。

同时也支持位运算,可以直接作与(交集)、或(并集)、异或等运算。

记得选C++14!

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
struct data
{
    int to,next;
}edge[500005];
int T,n,m,u,v,val[20005],cnt,inDegree[20005],order[20005],head[20005];
bool vis[20005];
bitset<20005> rec[20005];
void add(int u,int v)
{
    edge[++cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt;
}
int main()
{
    scanf("%d",&T);
    while (T>0)
    {
    	  //记得重置数组	
        T--;
        memset(head,0,sizeof(head));
        memset(edge,0,sizeof(edge));
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&val[i]);
            rec[i][i]=1;
        }
        cnt=0;
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add(v,u);//反向建图,便于统计
            inDegree[u]++;
        }
        cnt=0;
        queue<int> que;
        for (int i=1;i<=n;i++)
            if (!inDegree[i])
                que.push(i);
        while (!que.empty())
        {
            u=que.front();
            que.pop();
            order[++cnt]=u;
            for (int i=head[u];i;i=edge[i].next)
            {
                v=edge[i].to;
                inDegree[v]--;
                if (!inDegree[v]) que.push(v);
            }
        }//拓扑排序
        for (int i=1;i<=n;i++)
        {
            int u=order[i];
            for (int j=head[u];j;j=edge[j].next)
                rec[edge[j].to]|=rec[u];//求并集
        }
        for (int i=1;i<=n;i++) 
        {
            int ans=0;
            for (int j=1;j<=n;j++)
                if (rec[i][j]) ans+=val[j];//统计
            printf("%d ",ans);
            rec[i].reset();
        }
        printf("
");
        
    }
    return 0;
}

以上是关于SP4882 DAGCNT2 - Counting in a DAG的主要内容,如果未能解决你的问题,请参考以下文章

SP34096 DIVCNTK - Counting Divisors (general) min_25筛

hdu 4882 ZCC Loves Codefires(贪心)

HDU 2952 Counting Sheep

Counting Bits

LightOJ - 1148 Mad Counting(坑)

HDU 1264 Counting Squares(模拟)