Time Limit:1000MS | Memory Limit:10000K | |
Total Submissions:2504 | Accepted:940 |
Description
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
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
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
主要是 这次月赛 一个 背包问题 没AC!!! 下定决心好好看一下DP。 遗憾不想要第二次。 看一个DP相关的文档,中间 有提到 拓扑 排序。 所以,找了道题。 终于是对 topo 有点 理解了。
拓扑排序的资料:拓扑算法的演示动画
百度百科关于拓扑的概念: 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前。
不过资料这东西 , 刚开始看 , 还是 觉得很模糊。 重要的是自己 慢慢想清楚!
我现在对 拓扑的理解: 拓扑排序就是 将一个 有向无环图 的所有点 排成一个 序列 ,使这个序列 越往右 越小。
例如 此题中 如果给 a , b ,f, g 四个点 , 给一组 方向关系 a>b , b > f . 那么 满足 的 拓扑序列 就有
abfg abgf agbf gabf
四种。 大概就是这么个 意思。
看看这道具体的题。 输入的时候有点麻烦, 先构一个 DAG 图 (有向无环图,具体可以谷歌查查) ,然后 记录每个 点的入度, (主要就是理解 入度, 入度这东西我理解 就是 直接 通向这个点的路径 数, 如第一组 数据 , b,f 的入度就是1 , a,g 的入度就是0) 然后 从 入度为0 的点开始 DFS 深搜。 每次 取出 一个 点 ,就把 这个点 直接 限制的点 的入度 减一。 我自己更简单的理解就是,如 前文 的动画 演示 提供的一样, 每次 把没有 “上司”的 点取出来, “上司 ” 就是有多少直接管着这点的点。 然后 去掉 这个点后, 它的 下属 的上司数 就可以 减一了 ,重复 取 没有上司管的点 , 知道 取出 整个 topo 数列。
此题 我把所有 字母对应 为数字,。具体思路代码很详细。
此题的代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int cmp(const void *a,const void *b)
{
return *(int *)a - *(int *)b;
}
void dfs(int z,int count);
int a[25],dir[30][30],n,topo[25],vir[30],du[30]; //dir方向关系。du记录 度数。 vir标记是否访问。 a 数列 记录所有点。
int main()
{
// freopen("in.txt","r",stdin);
char ch[100];
int len,i;
while(gets(ch)!=NULL)
{
//初始化
memset(dir,0,sizeof(dir));
memset(vir,0,sizeof(vir));
memset(du,0,sizeof(du));
len=strlen(ch);
n=0;
//记录点
for(i=0;i<len;i++)
if(ch[i]<='z' && ch[i]>= 'a')
a[n++]= ch[i]-'a';
qsort(a,n,sizeof(int),cmp);
gets(ch);
len=strlen(ch);
int first=1,st,ed;
for(i=0;i<len;i++)
{
if(first && ch[i]<='z' && ch[i] >='a')
{
first=0;
st=ch[i]-'a';
continue;
}
if(!first && ch[i]<='z' && ch[i] >='a')
{
first=1;
ed=ch[i]-'a';
dir[st][ed]=1; //记录方向关系
du[ed]++; //记录度数
continue;
}
}
for(i=0;i<n;i++) if(!du[a[i]]) dfs(a[i],0); //从度数为0的点开始搜索
putchar('\n');
}
return 0;
}
void dfs(int z,int count)
{
int i;
topo[count]=z;
if(count==n-1) //所有点取完了,满足 ,输出。
{
for(i=0;i<n;i++)
printf("%c",topo[i]+'a');
printf("\n");
return ;
}
vir[z]=1; //标记 为 已访问。
for(i=0;i<n;i++)
{
if(!vir[a[i]] && dir[z][a[i]] )
du[a[i]] --; // 把“下属”的度数减一
}
for(i=0;i<n;i++)
if(!du[a[i]] && !vir[a[i]] ) //度数为0的继续取。
dfs(a[i],count+1);
//下面几行很重要。 图的状态要复原!。
for(i=0;i<n;i++)
{
if(!vir[a[i]] && dir[z][a[i]] )
du[a[i]] ++;
}
vir[z]=0;
}
PS: 很久没写过这么详细的 博客了 。。。。。 以前觉得写详细点 有利于 自己更好的 理解。但总写 又 影响 效率。 以后 觉得 很有价值的 就写详细点吧
O(∩_∩)O哈哈~。