hdu 4857(拓扑)

这题读完,马上想到是拓扑,但裸拓扑果断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]<<" ";
			else
				cout<<queu[i]<<endl;
		}
	}
	return 0;
}</span>



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值