首页 > 代码库 > hdu2647 逆拓扑,链式前向星。

hdu2647 逆拓扑,链式前向星。

原文地址


题目分析

题意

老板发工资,但是要保证发的工资数满足每个人的期望,比如A期望工资大于B,只需比B多1元钱即可。老板发的最低工资为888元。输出老板最少发的工资总数,若是无法满足大家的期望,则输出-1。

分析

很明显这是一个拓扑问题,若存在环则无法满足大家的期望。若按常理,A>B,则可能会建立A指向B的有向边。此题不然,因为我们只知道最少的钱数是888,所以从小到大进行拓扑排序更为恰当。所以是建立B指向A的有向边。此之为逆拓扑排序。因为这样处理后排序的结果与原先拓扑排序的顺序相反。

以图论观点来看,若为邻接矩阵存储就视作了矩阵的逆置。

链式前向星

链式前向星是图的一种存储方式,其实质是邻接表的静态存储。关于链式前向星的更多介绍,可移步《深度理解链式前向星》。

吐槽,链式前向星并非学术上的术语,貌似是国内网友的起名智慧。。因此国外没有这样的术语。不过这个词在国内还是有认可度的。

我的代码

用了点小技巧,比如static变量,还有重载构造函数等等。因此跑了359ms(g++)43ms(c++)。。囧。重度追求效率的童鞋可无视,本代码重在谈思路。

#include<iostream>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
using namespace std;
const int max_size=10001;
int n,m;
int head[max_size];
int in[max_size];
int reward[max_size];
queue<int> q;
struct Edge
{
    int to;
    int next;
    Edge(){};
    Edge(int i,int j):to(i),next(j){};
};
Edge edges[max_size*2];
void add(int i,int j)
{
    static int k=0;
    edges[k].to=j;
    edges[k].next=head[i];
    head[i]=k++;
    if(k==m)
        k=0;
}
void topo()
{
    for(int i=1;i<=n;i++)
    {
        if(in[i]==0)
        {
            reward[i]=0;
            q.push(i);
        }
    }
    int top;
    int to;
    while(!q.empty())
    {
        top=q.front();
        q.pop();
        for(int k=head[top];k!=-1;k=edges[k].next)
        {
            to = edges[k].to;
            in[to]--;
            if(in[to]==0)
                q.push(to);
            reward[to]=reward[top]+1;//多1块钱就行了。。
        }
    }
    int sum=n*888;
    for(int i=1;i<=n;i++)
    {
        if(reward[i]<0)
        {
            cout<<-1<<endl;//如果奖金(工资)数组reward中还有-1存在,说明有环。
            return;
        }
        sum+=reward[i];
    }
    cout<<sum<<endl;
}
int main()
{
    int i,j;
    while(cin>>n>>m)
    {
        memset(in,0,sizeof in);
        memset(head,-1,sizeof head);
        memset(reward,-1,sizeof reward);
        for(int t=0;t<m;t++)
        {
            cin>>i>>j;
            add(j,i);
            in[i]++;
        }
        topo();
    }
}


hdu2647 逆拓扑,链式前向星。