1. 程式人生 > >【模板題】【圖】拓撲排序 兩道例題,兩種思路:貪心策略及DFS

【模板題】【圖】拓撲排序 兩道例題,兩種思路:貪心策略及DFS

題目大意:給出一堆關係類似"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;
}

題目大意:給任務排序,並輸出順序。

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;
}