Sweety

Practice makes perfect

导航

(拓扑排序)||(全排序)Following Orders(11.3.1))

Posted on 2014-08-07 18:09  蓝空  阅读(151)  评论(0编辑  收藏  举报

Description

Order is an important concept in mathematics and in computer science. For example, Zorn's Lemma states: ``a partially ordered set in which every chain has an upper bound contains a maximal element.'' Order is also important in reasoning about the fix-point semantics of programs.


This problem involves neither Zorn's Lemma nor fix-point semantics, but does involve order.
Given a list of variable constraints of the form x < y, you are to write a program that prints all orderings of the variables that are consistent with the constraints.


For example, given the constraints x < y and x < z there are two orderings of the variables x, y, and z that are consistent with these constraints: x y z and x z y.

Input

The input consists of a sequence of constraint specifications. A specification consists of two lines: a list of variables on one line followed by a list of contraints on the next line. A constraint is given by a pair of variables, where x y indicates that x < y.


All variables are single character, lower-case letters. There will be at least two variables, and no more than 20 variables in a specification. There will be at least one constraint, and no more than 50 constraints in a specification. There will be at least one, and no more than 300 orderings consistent with the contraints in a specification.


Input is terminated by end-of-file.

Output

For each constraint specification, all orderings consistent with the constraints should be printed. Orderings are printed in lexicographical (alphabetical) order, one per line.


Output for different constraint specifications is separated by a blank line.

Sample Input

a b f g
a b b f
v w x y z
v y x v z v w v

Sample Output

abfg
abgf
agbf
gabf

wxzvy
wzxvy
xwzvy
xzwvy
zwxvy
zxwvy

 

 

开始用深度搜索的方式,结果没有想全面,这样做的话就会出现关系没法传递的现象,结果算法全部都是错误的,做了那么长时间,竟然一点都不对,哎。。。

#include<iostream>
#include <string>
#include <cstdio>
#include <cstring>
using namespace std;
bool map[150][150];
char ch[50],limit[150],temp[250];
string s;
int len2,len1;
void makemap()
{
	memset(map,0,sizeof(map));
	int i,j;
	for(i=0;i<len1;i++)
		for( j=0;j<len1;j++)
			if(ch[i]!=ch[j])
				map[ch[i]][ch[j]]=1;

	 for(i=0;i<len2;i+=2)
		 map[  limit[i+1]  ][  limit[i]  ]=0;

	 for(i='a';i<='z';i++)
	 {
		 for(int j='a';j<='z';j++)
			cout<<map[i][j]<<' ';
		 cout<<endl;
	 }
}



void dfs(int x,int k,string s)
{
	s=s+char(x);    //记录路径
	if(k==len1-1)     //记录路径的长度
	{
		cout<<s<<endl;
		return ;
	}
	for(int y='a';y<='z';y++)
		if(map[x][y])
		{
			string str="";
			for(int i='a';i<='z';i++)
				if(map[i][x]==1)
				{
					map[i][x]=0;
					str=str+char(i);
				}
			map[x][y]=0;
			dfs(y,k+1,s);
            for(int j=0;j<str.size();j++)//恢复原形状
				map[str[j]][x]=1;
			map[x][y]=1;

		}
}
int main ()
{
	int len;
	while(cin.getline(temp,30,'\n'))
	{
		int i=0;
		len=strlen(temp);
		int j=0;
		while(j<len)
		{
			if(temp[j]!=' ')
				ch[i++]=temp[j];
			j++;
		}
		ch[i]='\0';
		printf("%s\n",ch);
		i=j=0;
		cin.getline(temp,30,'\n');
		len=strlen(temp);
		while(j<len)
		{
			if(temp[j]!=' ')
				limit[i++]=temp[j];
			j++;
		}
		limit[i]='\0';
		printf("%s\n",limit);
		len2=strlen(limit);
        len1=strlen(ch);
		cout<<len1<<"&&&&&&&&&&&&&&&&&&&&&&&&&&"<<endl;
		makemap();
		for(i=0;i<len1;i++)
	     	dfs(ch[i],0,"");
	}


		return 0;
}


 

 

 拓扑排序,通过对节点和入度(产生限制)和出度(解除限制)来实现是否能访问该节点的作用

#include<iostream>
#include<cstring>
#include<string>
using namespace std;

int len;
int pre[300];    // 存字母入度
                 // 把小写字母的ascii码都包括在内
                 //入度和出度其实就是和树一样,不过在本算法中入度指的是收到来自其他字母的限制
bool has[300];  //节点标志   // 把小写字母的ascii码都包括在内,如果节点是1的话就能访问
string var,v;   //var 变量串  v 约束串 
void dfs(int dep,string res)
{
	if(dep==len)
	{                     //第n+1个字母不用找(即找完n个字母时结束)
		cout<<res<<endl;
		return ;
	}
	for(int i='a';i<='z';i++)//按字典顺序遍历查找入度为0的节点,释放该节点
		if( has[i] && pre[i]==0 ) //该节点存在且该节点没有被限制 
		{
			has[i]=false;//删除点,标记该点不能再访问了
			int k;
			for(k=0;k<v.length();k+=4)//该节点限制的所有的字母接触当前字母的限制,即减一
				if(v[k]==i)
					-- pre[ v[k+2] ] ;  //解除本限制
			 dfs(dep+1,res+char(i));   
			for(k=0;k<v.length();k+=4)//恢复被删边
				if(v[k]==i)
					++ pre[v[k+2]] ;
				has[i]=true;           //恢复节点
		}		
}
int main()
{
	while(getline(cin,var)&&getline(cin,v))
	{
		memset(pre,0,sizeof(pre));   //初始化节点标志,初始时都不是节点
		memset(has,0,sizeof(has));   //初始化节点入度,初始为都没有限制
		int i;
		for(i=0;i<var.length();i+=2)//初始节点标志
			has[ var[i] ]=true;
		len=var.length()/2 +1;  //n为节点数
		for(i=0;i<v.length();i+=4)//统计节点入度  v.lenth()=v.size()
			 ++ pre[ v[i+2] ] ;
		dfs(0,"");   //第一个参数为已经有多少个已经访问过的数
		cout<<endl;
	}
	return 0;
}



 

 

最笨的办法,将所有的全排列全部列出,然后筛选,不过由于后台的数据不是很多,所以不会超时,就是这道题的输入比较屌丝,其实由于输入是正确的。将输入的

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int len1,len2;
string t;
char ch[200], limit[200];

int cmp(const void* p, const void* q) 
{
	return *(char*)p - *(char*)q;
}//比较函数,从小到大排序

bool isvalid() 
{//
	char p, q;
	int i, j;      //i记录已经排好序的当前位置指针,j记录条件的当前位置
   
//	cout<<"进入判断:"<<endl;
//	cout<<"*************"<<ch<<endl<<limit<<endl<<"************"<<endl;
	for (j=0; j < len2; j++)
	{
		p = limit[j*2];
		q = limit[j*2+1];     //两个为一对
<span style="color:#ff0000;">		for (i=0; i <len1; i++)   //如果与条件冲突返回false
		{                
		   if (ch[i] == p) //如果先出现了前面一个,也就是顺序是对的,忽略掉本次循环
				break;
		   if (ch[i] == q) //如果是先出现了后面的那个,也就是顺序是错误的,就返回错误
			 return false;
		}
</span>	}
	return true;
}

int main()
{
	char temp [300];
	while(cin.getline(temp,50,'\n'))
	{
		int i=0;
		int len=strlen(temp);
		int j=0;
		while(j<len)
		{
			if(temp[j]!=' ')
				ch[i++]=temp[j];
			j++;
		}
		ch[i]='\0';
	 //	printf("%s\n",ch);
		i=j=0;
		cin.getline(temp,105,'\n');
		len=strlen(temp);
		while(j<len)
		{
			if(temp[j]!=' ')
				limit[i++]=temp[j];
			j++;
		}
	//	printf("%s\n",limit);
		limit[i]='\0';
		len1 = strlen(ch);
                  len2=strlen(limit);
		qsort(ch, len1, sizeof(char), cmp);//按字典序排序
		if (isvalid())
			printf("%s\n", ch);
		while<span style="color:#ff0000;">(next_permutation(ch, ch+len1))//</span>用STL中的求排列组合函数求所有序列,新的排列顺序为当前排序的下一个排列方式
			if (isvalid())//判断当前序列是否符合给出的限制条件
				printf("%s\n", ch);//符合输出
		printf("\n");
	}
	return 0;
}