hdu 2647 Reward 拓扑排序+向前星邻接表

传送门:hdu 2647 REward

题目大意

有个老板要给员工发工资,老板很善良想满足每个员工的要求 ,但是他很吝啬。

解题思路

先解释一下什么是向前星邻接表;
一般在一个图当中我们使用邻接矩阵表示连个点之间是否有边比如:E[i][v] = 1表示有边,如果等于0表示没有边,但是如果数据十分大的时候就会造成空间的浪费,而且内存也是不够的。那么我们就考虑使用邻接表了,(邻接表和邻接矩阵都是线性代数里面的概念),邻接表就是一种链表。我们一般是使用的时候是定义一个结构体,如下:

struct Edge{
    int v,nxt;//v保存的是被指向的节点,nxt表示头结点保存的边的序号,如果是-1表示指向空
}e[MAXN<<1];//存的是边

简单地来说nxt表示的是next表示与当前边起点一样的另一条边在弄的数组中的位置
比如我们构造一个有向图:
1 2
3 4
2 3
2 4
1 3
前面的指向后面的。对应的图如下:
这里写图片描述
我们先来看一下添加边的代码:

void initEdge()
{
    erear = 0;
    memset(head,-1,sizeof head);
    memset(OUT,0,sizeof OUT);
}

void addEdge(int u,int v)
{
    e[erear].v = v;//开始节点
    e[erear].nxt = head[u];//当前节点的下一个节点指向的头节点
    //将当前节点变为头节点
    head[u] = erear++;
}

那么建图的过程如下:
1. 首先要有”空”边这里写图片描述
2. 建立第一条边这里写图片描述
3. 因为前三条边都是一样的,所以前三条边建立之后为这里写图片描述
4. 当前节点的上一个节点不是空节点了,就可以连接了这里写图片描述
5. 建立之后如图:这里写图片描述

知道了这个之后我们就是通过头节点来进行访问的,代码如下:

for(int j=head[u];~j;j=e[j].nxt)
   {
         int v = e[j].v;
            ...
   }

这样优化空间就可以了。

AC代码

#include<cstdio>
#include<cstring>
#include<set>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 20000 + 5 ;
int out[MAXN],head[MAXN],erear;
int N,M,OUT[MAXN];
bool vis[MAXN];
struct Edge{
    int v,nxt;
}e[MAXN<<1];

void initEdge()
{
    erear = 0;
    memset(head,-1,sizeof head);
    memset(OUT,0,sizeof OUT);
}

void addEdge(int u,int v)
{
    e[erear].v = v;
    e[erear].nxt = head[u];
    head[u] = erear++;
}

int getAns()
{
    queue<int>Q;
    for(int i=1;i<=N;i++)
        if(OUT[i]==0) Q.push(i);
    int ranked = 0,ret = -1,sum = 0;
    while(!Q.empty())
    {
        int tmp = Q.size();
        ret += tmp*(ranked+888);
        for(int i=0;i<tmp;i++)
        {
            int u = Q.front();
            sum++;
            Q.pop();
            for(int j=head[u];~j;j=e[j].nxt)
            {
                int v = e[j].v;
                if(--OUT[v] == 0)
                    Q.push(v);
            }
        }
        ranked++;
    }
    if(sum!=N)return -1;
    return ret;
}

int main()
{
    int u,v;
    while(~scanf("%d%d",&N,&M))
    {
        initEdge();
        for(int i=0;i<M;i++)
        {
            scanf("%d%d",&v,&u);
            addEdge(u,v);
            OUT[v]++;
        }
        int ans = getAns();
        printf("%d\n",ans==-1?-1:ans+1);
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值