这题读完,马上想到是拓扑,但裸拓扑果断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>