POJ 1270 Following Orders

本文讨论了如何通过深搜算法解决特定约束条件下,使用不同字母进行序列排列的问题。详细介绍了输入格式、约束表达方式及算法实现,确保输出序列符合给定约束并按照字典序升序排列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:

       现有多个测例(测例以EOF结束),每个测例中第一行会给出要使用的小写字母(不少于2个不超过20个不同的小写字母,以空格隔开),第二行给出若干约束条件 ,约束条件不超过50个但至少有一条,约束形式如下"b a"表示b < a,即b必须排在a前面,对于每个测例都要求输出所有满足约束条件的序列,如果有多个序列满足要求则按照字典序升序逐行打印出来,并且输入保证一定有解(至少有1个解但不超过300个)。

题目链接

注释代码:

/*                                 
 * Problem ID : POJ 1270 Following Orders
 * Author     : Lirx.t.Una                                 
 * Language   : C++                     
 * Run Time   : 0 ms                                 
 * Run Memory : 124 KB                                 
*/ 

#include <algorithm>
#include <cassert>
#include <iostream>
#include <cstring>
#include <cstdio>

//最大字符数
#define	MAXN	20
//临时结束输入的字符串(按行读取)
#define	FMTLEN	205

using namespace std;

char	ch_set[MAXN + 1];//char_set,使用的字符集
char	mp[MAXN];//将字符集按照从小到大排序后映射成数组下标(因为要求按照字典序升序输出解)
char	deg[MAXN];//入度
bool	g[MAXN][MAXN];//图

char	fmt[FMTLEN];

char	path[MAXN + 1];//保存最后的结果

int		n;//使用的字符的个数,即字符集的大小
int		stp;//搜索的深度

void
dfs(void) {//按照字典序输出必定使用深搜

	int		i, j;

	if ( stp == n ) {
	
		path[stp] = '\0';
		puts(path);
		return ;
	}

	for ( i = 0; i < n; i++ )//每一层都从小到大扫入度为0的点
		if ( !deg[i] ) {
		
			path[stp++] = ch_set[i];
			deg[i]--;

			for ( j = 0; j < n; j++ )
				if ( g[i][j] )
					deg[j]--;

			dfs();

			for ( j = 0; j < n; j++ )//还原现场
				if ( g[i][j] )
					deg[j]++;
			deg[i]++;
			stp--;
		}
}

int
main() {

	int		i, j;//计数变量
	int		u, v;//临时点
	int		len;//临时字符串的长度

	while ( gets(fmt) ) {
	
		memset(g, false, sizeof(g));
		memset(deg, 0, sizeof(deg));

		n   = 0;
		len = strlen(fmt);

		for ( i = 0; i < len; i++ )//统计使用的字符个数放入ch_set中
			if ( ' ' != fmt[i] )
				ch_set[n++] = fmt[i];
		sort(ch_set, ch_set + n);//排序

		for ( i = 0; i < n; i++ ) mp[ ch_set[i] ] = i;//映射成数组下标

		gets(fmt);
		len = strlen(fmt);
		for ( i = 0; i < len; i++ )
			if ( fmt[i] != ' ' )
				for ( j = i + 1; j < len; j++ )
					if ( fmt[j] != ' ' ) {//两个两个筛出一组组关系
					
						u = mp[ fmt[i] ];
						v = mp[ fmt[j] ];

						if ( g[u][v] ) {//由于输入保证有解因此无需检查环以及回边
							
							i = j;//跳到下一组
							break;
						}
				
						//跟新边以及入度
						g[u][v] = true;
						deg[v]++;
						i = j;//同样跳到下一组关系
						break;
					}

		stp = 0;
		dfs();
		putchar('\n');
	}

	return 0;
}
无注释代码:

#include <algorithm>
#include <cassert>
#include <iostream>
#include <cstring>
#include <cstdio>

#define	MAXN	20
#define	FMTLEN	205

using namespace std;

char	ch_set[MAXN + 1];
char	mp[MAXN];
char	deg[MAXN];
bool	g[MAXN][MAXN];

char	fmt[FMTLEN];

char	path[MAXN + 1];

int		n;
int		stp;

void
dfs(void) {

	int		i, j;

	if ( stp == n ) {
	
		path[stp] = '\0';
		puts(path);
		return ;
	}

	for ( i = 0; i < n; i++ )
		if ( !deg[i] ) {
		
			path[stp++] = ch_set[i];
			deg[i]--;

			for ( j = 0; j < n; j++ )
				if ( g[i][j] )
					deg[j]--;

			dfs();

			for ( j = 0; j < n; j++ )
				if ( g[i][j] )
					deg[j]++;
			deg[i]++;
			stp--;
		}
}

int
main() {

	int		i, j;
	int		u, v;
	int		len;

	while ( gets(fmt) ) {
	
		memset(g, false, sizeof(g));
		memset(deg, 0, sizeof(deg));

		n   = 0;
		len = strlen(fmt);

		for ( i = 0; i < len; i++ )
			if ( ' ' != fmt[i] )
				ch_set[n++] = fmt[i];
		sort(ch_set, ch_set + n);

		for ( i = 0; i < n; i++ ) mp[ ch_set[i] ] = i;

		gets(fmt);
		len = strlen(fmt);
		for ( i = 0; i < len; i++ )
			if ( fmt[i] != ' ' )
				for ( j = i + 1; j < len; j++ )
					if ( fmt[j] != ' ' ) {
					
						u = mp[ fmt[i] ];
						v = mp[ fmt[j] ];

						if ( g[u][v] ) {
							
							i = j;
							break;
						}

						g[u][v] = true;
						deg[v]++;
						i = j;
						break;
					}

		stp = 0;
		dfs();
		putchar('\n');
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值