学拓扑排序还是想补题,先从水题入手,学到了一个最简单的拓扑排序,时间复杂度高达O(n ^ 3),也就水水题还行
比赛那道题要是这么做就MLE,要不然也得TLE哈哈哈
其实虽然方法水,和所有拓扑排序原理还是一样的,就是建图然后逐条删边,边删边输出
原理这里讲的很清楚了:拓扑排序
直接挂很水很水的代码,好的方法肯定要学,慢慢来。。。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int n, m;
bool vis[505][505];
int indegree[505];
void topo()
{
bool flag = 0;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
{
if(! indegree[j])
{
indegree[j] --; //防止重复判断
if(flag)printf(" ");
printf("%d",j);
flag = 1;
for(int k = 1; k <= n; k ++)
if(vis[j][k])
indegree[k] --;
break;//及时跳出进入i + 1层循环
}
}
}
int main()
{
while(scanf("%d %d", &n, &m) != EOF)
{
memset(vis, 0, sizeof(vis));
memset(indegree, 0, sizeof(indegree));
int a, b;
for(int i = 1; i <= m; i ++)
{
scanf("%d %d", &a, &b);
if(! vis[a][b])
{
vis[a][b] = 1;
indegree[b] ++;
}
}
topo();
printf("\n");
}
return 0;
}
然后是优先队列写法,这个时间复杂度低多了
注意priority_queue<int,vector<int>,greater<int> >,是优先队列元素从小到大排列,将greater改成less就变为从大到小
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int n, m;
int ind[505];
bool vis[505][505];
int to[505];
int cnt;
void topo()
{
priority_queue<int, vector<int>, greater<int> >q;
for(int i = 1; i <= n; i ++)
{
if(! ind[i])
q.push(i);
}
while(! q.empty())
{
int h = q.top();
q.pop();
to[cnt ++] = h;
for(int i = 1; i <= n; i ++)
{
if(vis[h][i])
{
ind[i] --;
if(! ind[i])q.push(i);
vis[h][i] = 0;
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&m) != EOF)
{
memset(vis, 0, sizeof(vis));
memset(ind, 0, sizeof(ind));
int a, b;
for(int i = 1; i <= m; i ++)
{
scanf("%d%d",&a,&b);
if(! vis[a][b])
{
vis[a][b] = 1;
ind[b] ++;
}
}
cnt = 0;
topo();
int flag = 0;
for(int i = 0; i < cnt; i ++)
{
if(flag)printf(" ");
printf("%d",to[i]);
flag = 1;
}
printf("\n");
}
return 0;
}
如果这道题的数据和比赛的时候一样大,怎么办,开一个50000*50000的数组肯定爆了,用vector很好的解决了这个问题,并且这种方法不用去重,原因也很简单,自己领会
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int n, m;
int ind[505];
int to[505];
int cnt;
int main()
{
while(scanf("%d%d",&n,&m) != EOF)
{
vector<int>e[505];
memset(ind, 0, sizeof(ind));
int a, b;
for(int i = 1; i <= m; i ++)
{
scanf("%d%d",&a,&b);
e[a].push_back(b);
ind[b] ++;
}
cnt = 0;
priority_queue<int, vector<int>, greater<int> >q;
for(int i = 1; i <= n; i ++)
{
if(! ind[i])
q.push(i);
}
while(! q.empty())
{
int h = q.top();
to[cnt ++] = h;
q.pop();
for(int i = 0; i < e[h].size(); i ++)
{
int H = e[h][i];
ind[H] --;
if(! ind[H])q.push(H);
}
}
int flag = 0;
for(int i = 0; i < cnt; i ++)
{
if(flag)printf(" ");
printf("%d",to[i]);
flag = 1;
}
printf("\n");
}
return 0;
}
然后这道题到此为止,做比赛题,然而然而然而然而一直wa,怎么改也不对,后来得知忽略了一个条件,那就是答案只有一个合理的存在,因为这道题的输出是有前提的,后来知道这个叫反向拓扑排序?
HDU – 4857
拓扑排序 这个博客讲的很详细,感觉自己还完全没有学会拓扑排序啊,哎哎继续刷题 AC代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int n, m;
int ind[50005];
int to[50005];
int cnt;
int main()
{
int t;
scanf("%d",&t);
while(t --)
{
scanf("%d%d",&n,&m);
vector<int>e[50005];
memset(ind, 0, sizeof(ind));
int a, b;
for(int i = 1; i <= m; i ++)
{
scanf("%d%d",&a,&b);
e[b].push_back(a);
ind[a] ++;
}
cnt = n;
priority_queue<int, vector<int>, less<int> >q;
for(int i = 1; i <= n; i ++)
{
if(! ind[i])
q.push(i);
}
while(! q.empty())
{
int h = q.top();
to[cnt --] = h;
q.pop();
for(int i = 0; i < e[h].size(); i ++)
{
int H = e[h][i];
ind[H] --;
if(! ind[H])q.push(H);
}
}
int flag = 0;
for(int i = 1; i <= n; i ++)
{
if(flag)printf(" ");
printf("%d",to[i]);
flag = 1;
}
printf("\n");
}
return 0;
}