poj 1496(1850)/2245 全组合打表(一种字符编码/Lotto)

题意:已知给定字符串只会有小写字符出现,而且最多5位。串中的字符必须从左到右严格递增。对应的数字规则为:a -> 1;b ->2 ... z -> 26;ab -> 27;ac -> 28 ... az -> 51;bc -> 52 ... vwxyz -> 83681。对给出的输入串,输入其对应的数字,如果不符合则输出0。

思路:考虑到一共只有83681个可行串,不算太大,便通过26个字母的全组合打表出所有的串,之后二分查找。

2245:相当于求含有6个元素的全组合

1496代码:

#include <stdio.h>
#include <string.h>
char s[83682][6],t[6],res[6];
int used[27];
int top=0;
void dfs(int d,int e,int f){
	int i;
	if(d == e){
		res[d] = '\0';
		strcpy(s[++top],res);//按顺序打入表中
		return ;	
	}
	for(i = f;i<26;i++)
		if(!used[i]){
			used[i] = 1;
			res[d] = i+'a';
			dfs(d+1,e,i+1);
			used[i] = 0;
		}
}
void create(){//求1~5在26个小写字母上的全组合
	int i;
	for(i = 1;i<=5;i++){
		memset(used,0,sizeof(used));
		dfs(0,i,0);
	}
}
int test(char x[6]){//判断串x是否可行
	int i;
	for(i=1;x[i]!='\0';i++)
		if(x[i] <= x[i-1])
			return 0;
	return 1;
}
int compare(char x[6],char y[6]){//比较两个串的先后,
	int len = strlen(x)-strlen(y);
	if(!len)//如果长度相同就比较字典序
		return strcmp(y,x);
	return len<0?1:-1;//细心注意谁大谁小
}
int find(char x[6]){//二分查找
	int low,high,mid,temp;
	low = 1;
	high = top;
	while(low <= high){
		mid = (low+high)>>1;
		temp = compare(s[mid],x);
		if(!temp)
			return mid;
		else if(temp < 0)
			high = mid-1;
		else
			low = mid+1;
	}
}
int main(){
	freopen("a.txt","r",stdin);
	create();//打表
	while(scanf("%s",t)!=EOF){
		if(test(t))//如果输入串可行
			printf("%d\n",find(t));
		else
			printf("0\n");
	}
	return 0;
}

2245:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
int s[15],len,res[10];
int n;
void dfs(int from){
    int i;
    if(len == 6){
        for(i = 1;i<=6;i++)
            printf("%d ",res[i]);
        printf("\n");
        return ;
    }
    for(i = from;i<=n;i++){
        res[++len] = s[i];
        dfs(i+1);
        len--;
    }
}
int main(){
    while(scanf("%d",&n) && n){
        int i;
        len = 0;
        for(i = 1;i<=n;i++)
            scanf("%d",&s[i]);
        dfs(1);
        printf("\n");
    }
    return 0;
}


1496(1850最多10个字符,和1496题意完全相同)的另一种dp思路:

dp[i][j]表示以字符 i 开头,长度为j的字符串的个数。dp[26][i]表示长度为i的字符串的总个数。每次对输入的字符串进行统计即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
int dp[27][12];
char s[12];
void init(){
    int i,j,k;
    clc(dp,0);
    for(i = 0;i<26;i++)
        dp[i][1] = 1;
    dp[26][1] = 26;
    for(j = 2;j<=10;j++)
        for(i = 0;i<26;i++){
            for(k = i+1;k<26;k++)
                dp[i][j] += dp[k][j-1];
            dp[26][j] += dp[i][j];
        }
}
int test(char* s){
    for(int i = 1;s[i];i++)
        if(s[i] <= s[i-1])
            return 0;
    return 1;
}
int main(){
    init();
    while(scanf("%s",s) != EOF){
        int i,j,len,num=0;
        if(test(s)){
            len = (int)strlen(s);
            for(i = 1;i<len;i++)
                num += dp[26][i];
            for(i = 0;i<s[0]-'a';i++)
                num += dp[i][len];
            for(i = 1;s[i];i++)
                for(j = s[i-1]-'a'+1;j<s[i]-'a';j++)
                    num += dp[j][len-i];
            printf("%d\n",num+1);
        }else
            printf("0\n");
    }
    return 0;
}


你可能感兴趣的:(poj 1496(1850)/2245 全组合打表(一种字符编码/Lotto))