poj1094

8 篇文章 0 订阅

使用删边法进行了拓扑排序,而DFS 法则可以直接判断是否有环路,但dfs无法判断是否会有多种拓扑序列,

所以可以用删边法不断地 搜索 。

这里给大家推荐两篇不错的关于拓扑排序博文:http://blog.csdn.net/dm_vincent/article/details/7714519

                                                                                     http://www.cnblogs.com/shanyou/archive/2006/11/16/562861.html

(前几天打了几道dp的题目,有点伤心。。。。)

#include <iostream>
using namespace std;

const int maxn = 30;
int map[maxn][maxn];//图邻接矩阵
bool tl[maxn];//可达性矩阵,用于判断是否产生环路
bool visited[maxn];//dfs 时判断结点是否访问过
int pre[maxn];//各个结点的入度

bool topo = true;//是否需要拓扑
bool only = false;//拓扑排列是否唯一

void dfs(int n)//计算n的 可达性矩阵
{
	tl[n] = true;
	visited[n] = true;
	for(int i = 0;i < maxn;i++)
	{
		if(1==map[n][i] && visited[i]==false)
			dfs(i);
	}
}


void solve(int num,int ques)//结点和询问数量
{
	topo= true;
	only = false;
	//邻接矩阵,可达性矩阵初始化
	memset(map,0,sizeof(map));
	memset(tl,0,sizeof(tl));
	memset(pre,0,sizeof(pre));

	char ch1,ch2,c;
	int relations = 0;
	for(int i = 0;i < ques;i++)
	{
		cin>>ch1>>c>>ch2;
		int m = ch1 - 'A';
		int n = ch2 - 'A';
		map[m][n] = 1;
		pre[n]++;
		
		memset(tl,false,sizeof(tl));
		memset(visited,false,sizeof(visited));
		
		//对n 进行深搜
		dfs(n);
		//存在反向边
		if(true==tl[m])
		{
			topo = false;//不需要进行拓扑排列
			relations = i + 1;
			break;
		}

		//尝试进行拓扑排序,Q 为拓扑排序 序列
		int Q[maxn];
		memset(Q,0,sizeof(Q));
		int tot = 0;//统计ru度数为零的结点,超尾指针!!!!!!!!!!!!!
		for(int k = 0;k < num;k++)
			if(0==pre[k])
				Q[tot++] = k;

		if(tot==1)//只有一个度数为零的结点
		{
			//使用删边法
			only = true;//有可能产生唯一拓扑排序
			int count = 0;//统计每次新增 度数为1 的结点数
			while(tot < num)
			{
				count = 0;
				//注意 tot是超尾指针
				int tmpoint = Q[tot - 1];
				//使用删边法,计算拓扑序列
				for(int k = 0;k < num;k++)
				{
					if(1==map[tmpoint][k])
					{
						//count++; 失误
						pre[k]--;
						if(0==pre[k])
						{
							Q[tot++] = k;
							count++;
						}
					}
				}//for 
				//若count > 1 则 拓扑序列不唯一,不用继续删边法,同时应该将删除的边恢复  处理下一关系
				if(count > 1)
				{
					for(int i = 0;i < num;i++)
					{
						if(1==map[tmpoint][i])
							pre[i]++;
					}
					only = false;
					break;
				}
			}//while

			if(only && tot==num)//产生了唯一拓扑排序
			{
				cout<<"Sorted sequence determined after "<<i + 1<<" relations: ";
				for(int i = 0;i < num;i++)
					cout<<char('A' + Q[i]);
				cout<<"."<<endl;
				//在屏蔽掉后续输入后 ,计算下一样例
				for(int bi = 0;bi < (ques - i - 1);bi++)
					cin>>ch1>>c>>ch2;
				break;
			}
			else //没有产生唯一的拓扑排序,那么恢复删除的边
			{
				memset(pre,0,sizeof(pre));
				for(int j = 0;j < num;j++)
					for(int k = 0;k < num;k++)
						if(1==map[j][k])
							pre[k]++;
			}
		}//if 只有一个度数为一的节点
		else//有多个度数唯一的结点则处理下一关系
		{
			continue;
		}

	}//for,处理下一关系
	//存在反向边
	if(!topo)
	{
		cout<<"Inconsistency found after "<<relations<<" relations."<<endl;
		for(int i = 0;i < ques -relations;i++)
			cin>>ch1>>c>>ch2;
	}
	else if(!only)
		cout<<"Sorted sequence cannot be determined."<<endl;
}


int main()
{
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	int nu,qu;
	while(cin>>nu>>qu)
	{
		if(nu || qu)
			solve(nu,qu);
		else
			break;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值