【模板题】拓扑排序 两道例题,两种思路:贪心策略及DFS

1094:Sorting It All Out

题目大意:给出一堆关系类似"A<B",有三种结果:1)在第k个关系读入后出现环路,2)在第k个关系读入后能够确定排序,3)无法确定顺序。

注意:
1、出现结果1、2之后之后的s要读但是操作略过
2、要判断重复的边(入度不能重复加)

3、要先判断环路再判断是否有多个入度为0的点(即没有全部排序)

#include<iostream>
#include<string.h>
#include<string>
#include<queue>
using namespace std;
int n,m,ans,opt;
bool g[27][27];
int gin[27];
char sortout[27];
int top;
bool topo(int c)
{
	queue<int> Q;
	int i,u,tin[27];
	bool unsure=false;
	for (i=1;i<=n;i++)
		if (gin[i]==0)
			Q.push(i);
	top=0;
	memcpy(tin,gin,sizeof(gin));
	while(!Q.empty())
	{
		if (Q.size()>1)
			unsure=true;//多个入度为1,肯定没有全部排序
		u=Q.front();Q.pop();
		sortout[top++]=u+'A'-1;
		for (i=1;i<=n;i++)
			if (g[u][i])
			{
				tin[i]--;
				if (tin[i]==0)
					Q.push(i);
			}
	}
	//注意先判断环路,才判断无结果!
	if (top<n)//节点没有输出完就已经没有入度为0的点则有环
	{ opt=2;ans=c;return 1;  }
	else if (unsure)
		return 0;
	else//top==n
	{ opt=1;ans=c;return 1;  }
	return 0;
}

void solve()
{
	int i,a,b;
	string s;
	bool flag=false;
	memset(g,0,sizeof(g));
	memset(gin,0,sizeof(gin));
	for (i=1;i<=m;i++)
	{
		cin>>s;
		if (flag)
			continue;
		a=s[0]-'A'+1;b=s[2]-'A'+1;
		if (g[b][a])//有环
		{
			opt=2;ans=i;
			flag=true;continue;
		}
		if (!g[a][b])//判断之前是否插入过该条边
		{
			g[a][b]=true;
			gin[b]++;
		}
		flag=topo(i);
	}
	if (!flag)
		opt=3;
}
int main()
{
	int i;
	while(cin>>n>>m)
	{
		if (n==0&&m==0)
			break;
		solve();
		if (opt==1)
		{
			cout<<"Sorted sequence determined after "<<ans<<" relations: ";
			for (i=0;i<top;i++) cout<<sortout[i];
			cout<<"."<<endl;
		}
		else if (opt==2)
			cout<<"Inconsistency found after "<<ans<<" relations."<<endl;
		else cout<<"Sorted sequence cannot be determined."<<endl;
	}
	return 0;
}

10305 - Ordering Tasks

题目大意:给任务排序,并输出顺序。

ps:还是使用贪心比较好,DFS比较耗时

贪心解法:

#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
int n,m;
bool g[101][101];
int gin[101];
int c[101];
int top;
void topo()
{
	int i;
	int u;
	top=0;
	queue<int> Q;
	for (i=1;i<=n;i++)
		if (gin[i]==0)
			Q.push(i);
	while(!Q.empty())
	{
		u=Q.front();Q.pop();
		c[top++]=u;
		for (i=1;i<=n;i++)
		{
			if (g[u][i])
			{
				gin[i]--;
				if (gin[i]==0)
					Q.push(i);
			}
		}
	}
}
int main()
{
	int i,a,b;
	while(cin>>n>>m)
	{
		if (n==0&&m==0)
			break;
		memset(g,0,sizeof(g));
		memset(gin,0,sizeof(0));
		for (i=0;i<m;i++)
		{
			cin>>a>>b;
			g[a][b]=1;
			gin[b]++;
		}
		topo();
		for (i=0;i<top-1;i++)
			cout<<c[i]<<" ";
		cout<<c[i]<<endl;
	}
	return 0;
}

DFS解法:

//AC
#include<iostream>
#include<vector>
#include<string.h>
using namespace std;
bool g[105][105]={0};
int n,m;
int c[200];
int topo[200], t;
bool dfs(int u)
{
	c[u] = -1; //访问标志
	for(int v = 1; v <= n; v++) 
		if(g[u][v]) 
		{
			if(c[v]<0) return false; //存在有向环,失败退出
			else if(!c[v] && !dfs(v)) 
					return false;
		}
	c[u] = 1; topo[--t]=u;
	return true;
}
bool toposort( )
{
	t = n;
	memset(c, 0, sizeof(c));
	for(int u = 1; u <= n; u++) 
		if(!c[u])
			if(!dfs(u)) 
				return false;
	return true;
}
int main()
{
	int i,j,x,y,count,point;
	while(cin>>n>>m)
	{
		if (n==0 && m==0)
			break;
		memset(g,0,sizeof(g));
		for (i=1;i<=m;i++)
		{
			cin>>x;cin>>y;
			g[x][y]=1;
		}
		toposort();
		for (i=0;i<n-1;i++)
			cout<<topo[i]<<" ";
		cout<<topo[i]<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/always_ease/article/details/80657462
今日推荐