现在的位置: 首页 > 综合 > 正文

UVA 10029 Edit Step Ladders

2018年03月17日 ⁄ 综合 ⁄ 共 1985字 ⁄ 字号 评论关闭

大意不再赘述。

思路:一开始一看题目就知道是有向无环图上的最长路径,但是有一个问题-->建图非常麻烦,一个字符串要经过三次变换,而且要与之前的字符串相比较看是否可以连边,建图这一部分我还没太想清楚,字符串的处理可以用hash来处理,但怎么去建图呢?25000个点额。

于是去网上查了下资料,发现有一个人处理得很巧妙。

即:用一个hash表将所有的字符串存起来,对于当前字符串,直接判断是否可以连边,连边的条件:通过三次变换该字符串A可以得到hash表中的某个字符串B,而且是字典序,这样才能保证是DAG图。

对于该字符串,我们也没必要直接去连边,如果该字符串通过一次变化可以得到它的话,那么直接进行记忆化搜索,这样就省去了建图的难题。

hash函数的选取最好是选用ELHhash,因为效率够快,而且稳定。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;

typedef unsigned long UL;

const int MAXN = 10000003; //果然还是要够大 

int first[MAXN];

int next[25010];
int d[25010];

bool vis[25010];

char st[25010][20];
char temp[20];

int n;

void init()
{
	n = 0;
	memset(vis, 0, sizeof(vis));
	memset(first, -1, sizeof(first));
}

int ELHhash(char *key)
{
    UL h = 0;
    while(*key)
    {
        h = (h<<4) + *key++;
        UL g = h & 0xf0000000L;
        if(g) h ^= g>>24;
        h &= ~g;
    }
    return h%MAXN;
}

int find(char *str)
{
	int h = ELHhash(str);
	for(int v = first[h]; v != -1; v = next[v])
	{
		if(!strcmp(st[v], str)) return v;
	}
	return -1; //没找到
}

void insert(int s)
{
	int h = ELHhash(st[s]);
	next[s] = first[h];
	first[h] = s;
}

void del(char *str, char *temp, int p)
{
	int j = 0;
	for(int i = 0; str[i]; i++) if(i != p)
	{
		temp[j++] = str[i];
	}
	temp[j] = '\0';
}

void add(char *str, char *temp, int p, char c)
{
	int j = 0;
	int len = strlen(str);
	for(int i = 0; i <= len; i++)
	{
		if(i == p)
		{
			temp[j++] = c;
		}
		temp[j++] = str[i];
	}
	temp[j] = '\0';
}

void repl(char *str, char *temp, int p, char c)
{
	int j = 0;
	for(int i = 0; str[i]; i++)
	{
		if(i == p) temp[j++] = c;
		else temp[j++] = str[i];
	}
	temp[j] = '\0';
}

int dp(int s)
{
	if(vis[s]) return d[s];
	vis[s] = 1;
	int &ans = d[s];
	ans = 1;
	int len = strlen(st[s]);
	for(int i = 0; i <= len; i++)
	{
		for(char c = 'a'; c <= 'z'; c++)
		{
			add(st[s], temp, i, c);
			int p = find(temp);
			if(p != -1 && strcmp(st[s], temp) < 0)
			{
				ans = max(ans, dp(p) + 1);
			}
		}
	}
	for(int i = 0; i < len; i++)
	{
		del(st[s], temp, i);
		int p = find(temp);
		if(p != -1 && strcmp(st[s], temp) < 0)
		{
			ans = max(ans, dp(p) + 1);
		}
	}
	for(int i = 0; i < len; i++)
	{
		for(char c = 'a'; c <= 'z'; c++)
		{
			repl(st[s], temp, i, c);
			int p = find(temp);
			if(p != -1 && strcmp(st[s], temp) < 0)
			{
				ans = max(ans, dp(p) + 1);
			}
		}
	}
	return ans;
}

void read_case()
{
	init();
	while(~scanf("%s", st[n]))
	{
		insert(n);
		n++;
	}
}

void solve()
{
	read_case();
	int ans = 0;
	for(int i = 0; i < n; i++)
	{
		ans = max(ans, dp(i));
	}
	printf("%d\n", ans);
}

int main()
{
	solve();
	return 0;
}

抱歉!评论已关闭.