zoukankan      html  css  js  c++  java
  • 搜索系列——Anagram(全排列)

    Anagram

    Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 20000/10000K (Java/Other)
    Total Submission(s) : 16   Accepted Submission(s) : 3
    Problem Description
    You are to write a program that has to generate all possible words from a given set of letters.
    Example: Given the word "abc", your program should - by exploring all different combination of the three letters - output the words "abc", "acb", "bac", "bca", "cab" and "cba".
    In the word taken from the input file, some letters may appear more than once. For a given word, your program should not produce the same word more than once, and the words should be output in alphabetically ascending order.
     

    Input
    The input consists of several words. The first line contains a number giving the number of words to follow. Each following line contains one word. A word consists of uppercase or lowercase letters from A to Z. Uppercase and lowercase letters are to be considered different. The length of each word is less than 13.
     

    Output
    For each word in the input, the output should contain all different words that can be generated with the letters of the given word. The words generated from the same input word should be output in alphabetically ascending order. An upper case letter goes before the corresponding lower case letter.
     

    Sample Input
    3 aAb abc acba
     

    Sample Output
    Aab Aba aAb abA bAa baA abc acb bac bca cab cba aabc aacb abac abca acab acba baac baca bcaa caab caba cbaa
     

    Source
    PKU


    还是一题回溯加dfs,题目要求是字母全排列,据说C++有个函数能够实现,但这里要求按字母表排列,而且在同一个字母的条件下,大写比小写要排前。于是我就用纯C做了。
    我的思路是构造两个数组ch和val来储存字母和字母的值,字母的值转化成数值储存,比如a是0.5, b是1.5,A是0,B是1,然后从小大排序,然后dfs前序遍历输出就是题目要求的输出了。

    但是,编完后发现一个很大的问题,在有重复字母的情况下会输出重复的排列。。。
    代码如下(未AC)

    #include<stdio.h>
    #include<string.h>
    
    float val[13];
    int num, res[13];
    char ch[13];
    
    void dfs(int cur)
    {
    	if (cur == num)
    	{
    		for (int i = 0; i < num; i++)
    			printf("%c", ch[res[i]]);
    		printf("\n");
    		return;
    	}
    	for (int i = 0; i < num; i++)
    	{
    		int ok = 1;
    		res[cur] = i;
    		for (int j = 0; j < cur; j++)
    			if (res[j] == i) 
    			{
    				ok = 0;
    				break;
    			}
    		if (ok)
    			dfs(cur + 1);
    	}
    	return;
    }
    
    int main()
    {
    	int n;
    	num = 0;
    	scanf("%d", &n);
    	while (n--)
    	{
    		num = 0;
    		scanf("%s", ch);
    		for (int i = 0; ch[i] != '\0'; i++)
    		{
    			num++;
    			if (ch[i] >= 'A'&& ch[i] <= 'Z')
    				val[i] = ch[i] - 'A';
    			else
    				val[i] = ch[i] - 'a' + 0.5;
    		}
    		for (int i = 0; i < num; i++)
    			for (int j = i + 1; j < num; j++)
    				if (val[i] > val[j])
    				{
    					float e = val[i];
    					val[i] = val[j];
    					val[j] = e;
    					char t = ch[i];
    					ch[i] = ch[j];
    					ch[j] = t;
    				}
    		dfs(0);
    	}
    	return 0;
    }




    结果,剪枝剪了半天不了,果然我太弱了。。。

    参考网上的解题报告,发现好多都是用的C++里面的stl里面的next_permutation函数,找到一个dfs的,照着剪枝,提交后老超时,我还以为是我手工排序比sort慢,又改又超时,改了几次之后来越像人家的代码,后来干脆把他的代码贴上去,也是超时!

    好坑!

    剪枝后代码如下(未AC)

    #include<stdio.h>
    #include<string.h>
    
    float val[13];
    int num, res[13], visited[13];
    char ch[13];
    
    void dfs(int cur)
    {
    	if (cur == num)
    	{
    		for (int i = 0; i < num; i++)
    			printf("%c", ch[res[i]]);
    		printf("\n");
    		return;
    	}
    	for (int i = 0; i < num; i++)
    		if (!visited[i])
    		{
    			res[cur] = i;
    			visited[i] = 1;
    			dfs(cur + 1);
    			visited[i] = 0;
    			while(i + 1 < num && val[i] == val[i + 1])
    				i++;
    		}
    }
    
    int main()
    {
    	int n;
    	num = 0;
    	scanf("%d", &n);
    	while (n--)
    	{
    		memset(visited, 0, sizeof(visited));
    		num = 0;
    		scanf("%s", ch);
    		for (int i = 0; ch[i] != '\0'; i++)
    		{
    			num++;
    			if (ch[i] >= 'A'&& ch[i] <= 'Z')
    				val[i] = ch[i] - 'A';
    			else
    				val[i] = ch[i] - 'a' + 0.5;
    		}
    		for (int i = 0; i < num; i++)   //sort
    			for (int j = i + 1; j < num; j++)
    				if (val[i] > val[j])
    				{
    					float e = val[i];
    					val[i] = val[j];
    					val[j] = e;
    					char t = ch[i];
    					ch[i] = ch[j];
    					ch[j] = t;
    				}
    		dfs(0);
    	}
    	return 0;
    }



    我决定用STL了。。。

    代码如下(已A):

    #include<iostream>
    #include<algorithm>
    #include<string>
    #include<cstring>
    using namespace std;
    
    bool cmp(char a, char b)
    {
    	double t1 = a, t2 = b;
    	if (a >= 'A' && a <= 'Z')
    		t1 += 31.5;
    	if (b >= 'A' && b <= 'Z')
    		t2 += 31.5;
    	return t1 < t2;
    }
    
    int main()
    {
    	int n, len;
    	char str[15];
    	cin >> n;
    	while(n--)
    	{
    		cin >> str;
    		len = strlen(str);
    		sort(str, str + len, cmp);
    		do
    		{
    			cout << str << endl;
    		}
    		while(next_permutation(str, str + len, cmp));
    	}
    	return 0;
    }


    以后要多用地点比较方便的函数,当然到需要时要会手操。。

  • 相关阅读:
    windowsserver2016系统性能和功能对比介绍
    联想x3650m5服务器安装windows2008R2系统
    Linux修改主机名
    Windows Server 2008 R2 忘记密码的处理方法
    Centos7 安装教程(详细版)
    CentOS 6.5的安装详解(图文详解)
    centos 6.5 忘记用户名和密码
    磁盘阵列的区别和特点
    什么是OSI参考模型?
    MTU是什么?
  • 原文地址:https://www.cnblogs.com/java20130723/p/3212177.html
Copyright © 2011-2022 走看看