hdu 4857(拓扑)

来源:互联网 发布:c语言求2的n次平方 编辑:程序博客网 时间:2024/04/29 16:28

这题读完,马上想到是拓扑,但裸拓扑果断wa了。在仔细分析一下,应该加个优先队列,结果又wa了。没办法,参考了下大牛。原来还要拓扑的反向建边。先说拓扑。

拓扑的作用就是排列一组相互有前后关系的数据的算法。最经典的例子就是课程安排。如果让你给一个班级安排课程,有识字,组词,造句,写文章,小学数学。你要如何安排呢?如果是我,果断就是刚才的顺序,先识字,在组词,造句,最后写文章,至于数学,放哪里都行。你在无形中就用到了拓扑排序。拓扑就是本着一些东西必须在另一些东西之前的原则排序的。你不可能还没识字,就让写文章吧。这个算法放到本题,真是太贴切了。下面就介绍一下拓扑的算法思路。介绍之前,必须说一下入度这个名词。所谓入度就是......还是先贴张图再说吧。


画的丑,能说明问题就行。看上图,1的入度0,2的入度2,3的入度0,4的入度1.好了感觉不需要再解释了。

明白入度后就简单了。拓扑的思路就是每次取出入度为0的点,然后把与它相连的点的入度减一,就这样循环,直到所有的点都被取出。像上面的图。第一次取1或3。假设我们取1

则删去1点,1点与2点相连,把2点的入度减一。此时,再取入度为0的点,只能是3了。2与3连,再把2的入度减一,此时2的入度就为0,取出2,4与2相连,4的入度减一,此时4的入度为0,再取出4,结束。保存数据时,可以用个二维数组,第一维代表操作点,第二维代表与操作点相连的点。入度则用一个一维数组保存即可。核心代码

<span style="font-size:18px;">for(int i=1;i<n;i++){cin>>a>>b;if(!arr[a][b])//防重复,比如数据为1,2  1,2 {arr[a][b]=1;rd[b]++;//入度 }}</span>
下面介绍一下优先队列,这个不需要过多解释,只给出几种实现形式就够了。

1 c++默认

priority_queue<int> q;默认是按优先级从大到小排列。

2  自定义优先级

struct cmp
{


operator bool ()(int x, int y)


{
return x > y; // x小的优先级高


//也可以写成其他方式,如: return p[x] > p[y];表示p[i]小的优先级高
}
};


priority_queue<int, vector<int>, cmp>q;//定义方法

3  结构体形式

struct node
{
int x, y;


friend bool operator < (node a, node b)
{
return a.x > b.x; //结构体中,x小的优先级高
}
};


priority_queue<node>q;//定义方法


//在该结构中,y为值, x为优先级。

当这些东西懂清楚以后,这题就是1+1了。就是2者结合就行了。上本题代码

<span style="font-size:18px;">#include<iostream>#include<vector>#include<queue>#include<cstring>using namespace std;int rd[30005];int queu[30005];vector<int> a[30005];int n,m;struct cmp{bool operator () (const int &a,const int &b){return a<b;}};priority_queue<int,vector<int>,cmp> q;void topo(){for(int i=1;i<=n;i++){if(rd[i]==0){q.push(i);}}int count=1;while(!q.empty()){int x=q.top();q.pop();for(int i=0;i<a[x].size();i++){rd[a[x][i]]--;if(rd[a[x][i]]==0){q.push(a[x][i]);}}queu[count++]=x;}}int main(){int t;cin>>t;while(t--){cin>>n>>m;for(int i=0;i<=n;i++){rd[i]=0;a[i].clear();}int x,y;while(m--){scanf("%d%d",&x,&y);a[y].push_back(x);rd[x]++;<span style="font-family: 'Microsoft YaHei', lucida, verdana, sans-serif;">//这里就是反向建边,仔细看就so easy。</span>}topo();for(int i=n;i>0;i--){if(i!=1)cout<<queu[i]<<" ";elsecout<<queu[i]<<endl;}}return 0;}</span>



0 0