UVA - 11604 General Sultan 题解

题目大意:

  有若干模式串,将某些模式串拼接起来(一个可以使用多次)形成一个长模式串,判断能否有两种或更多种不同的拼法拼成相同的模式串。

思路:

  神奇的构图,暴力的求解。

  可以发现,若有不同的拼法,则一个模式串的前缀要与一个模式串的后缀相同。

  因此我们就将问题转化成:从两个模式串开始,不停的按照前后缀匹配,最后达到两个串同时在一个点结束。

  那么,将每一个串的每一个字符都看作一个点,n2len2暴力枚举i串从z开始的后缀和j串(自己也可以,但不能让前缀是其本身)的前缀做匹配,看是否能将其中一个串匹配完。

  当(i,z)和j匹配,若i先结束了,则将(i,z)这个点连边到j串没匹配的第一个点,表示下一次匹配应该是从j的那个位置开始当后缀再寻找其他前缀;如果j先结束,与之前一个类似;如果i和j同时结束,则连边到终点。

  最后用dfs判断能否从某个模式串的第一个点开始走到终点。

  PS:1、fromhttp://blog.csdn.net/houserabbit/article/details/38943645

     2、数组的意义、范围要清楚,我花了一个多小时才发现数组开小了。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int M=109,N=30;
 5 int n,e,t,i,j,k,z,cnt,v[M*M*N*N],id[M][N],nex[M*M*N*N],len[M],head[M*N];
 6 bool vis[M*N],flag;
 7 char s[M][N];
 8
 9 void add(int x,int y) { v[++cnt]=y,nex[cnt]=head[x],head[x]=cnt; }
10
11 void dfs(int x)
12 {
13     if (x==e) { flag=1; return; }
14     vis[x]=1;
15     for (int i=head[x];~i;i=nex[i])
16         if (!vis[v[i]])
17         {
18             dfs(v[i]);
19             if (flag) return;
20         }
21 }
22
23 int main()
24 {
25     while (~scanf("%d",&n))
26     {
27         if (!n) break;
28         e=cnt=flag=0;
29         for (i=1;i<=n;++i)
30         {
31             scanf("%s%s",s[i],s[i]);
32             len[i]=strlen(s[i]);
33             for (j=0;j<len[i];++j) id[i][j]=++e;
34         }
35         for (++e,i=0;i<=e;++i) head[i]=-1;
36         for (i=1;i<=n;++i)
37             for (z=0;z<len[i];++z)
38                 for (j=1;j<=n;++j)
39                 {
40                     if (i==j && !z) continue;
41                     for (k=0;k<len[j] && z+k<len[i];++k)
42                         if (s[i][z+k]!=s[j][k]) break;
43                     if (z+k==len[i] && k==len[j]) add(id[i][z],e);
44                     else if (k==len[j]) add(id[i][z],id[i][z+k]);
45                          else if (z+k==len[i]) add(id[i][z],id[j][k]);
46                 }
47         for (i=0;i<=e;++i) vis[i]=0;
48         for (i=1;i<=n;++i)
49         {
50             if (!vis[id[i][0]]) dfs(id[i][0]);
51             if (flag) break;
52         }
53         printf("Case #%d: ",++t);
54         if (flag) puts("Ambiguous."); else puts("Not ambiguous.");
55     }
56     return 0;
57 }
时间: 2024-08-09 10:42:57

UVA - 11604 General Sultan 题解的相关文章

UVA - 11604 General Sultan(构图暴力)

题目大意:给出n个字符串(01串),问是否存在一个二进制序列,存在至少两种编码方式 比如{a = 01011111, b = 0101, c = 1111010, d = 010} 二进制序列01011111010就有两种编码方式了,可以由a+d组成,也可以由b+c+d组成(注意这里的二进制序列不是指所给的武器的二进制序列,刚开始没理解..被坑了) 解题思路:这样就比较好理解了,字符串匹配,不断的匹配 首先为每个字符都构建一个点,那怎么连边呢? 找匹配的部分进行连边,假设有两个字符串i,j,现在

Uva 167 The Sultan&#39;s Successors

题目链接:Uva 167 思路:     八皇后问题,采用回溯法解决问题. 代码: #include <iostream> #include <string.h> using namespace std; const int MAX_N = 10; int A[MAX_N]; int M[MAX_N][MAX_N]; int num, Max = 0; int is_safe( int row, int col ) { for ( int i = 0; i < row; ++

uva 167 - The Sultan&amp;#39;s Successors(典型的八皇后问题)

这道题是典型的八皇后问题,刘汝佳书上有具体的解说. 代码的实现例如以下: #include <stdio.h> #include <string.h> #include <stdlib.h> int vis[100][100];//刚開始wrong的原因就是这里数组开小了,开了[8][8],以为可以.后来看到[cur-i+8]意识到可能数组开小了.改大之后AC. int a[8][8]; int C[10]; int max_,tot; void search_(int

UVA 11729 Commando War 题解

“Waiting for orders we held in the wood, word from the front never came By evening the sound of the gunfire was miles away Ah softly we moved through the shadows, slip away through the trees Crossing their lines in the mists in the fields on our hand

【Uva 11604 编码都有歧义了】

·你的目的就是要让编码有歧义,这就美妙了. ·英文题,述大意:       给出n个模板字符串,询问是否存在一个字符串,使得用模板串(随便你用多少个)来拼凑这个串,能够至少有两种拼法.如果有,就输出“有”. ·分析:      值得注意的是,n的范围不太大(0<n<101).      如果直接思考如何拼凑,那么就是一个典型的搜索枚举思想,对于这道题来说,也是一个典型的爆炸超时思想.不过,如果拥有一个好的习惯,你会不禁想到:正着不行反着来.所以,我们考虑对于一个串,把它切成几块,并使得每块都属

uva 11388 GCD LCM题解

题意:输入两个数G,L,找出两个数a,b,使得gcd(a,b)=G,lcm(a,b)=L.有多解输出a最小的那个.无解输出-1. 嗯,这是一道值得思考5s的题目. L%G==0即有解,否则无解. 有解的话我们让a=G,b=L.这样a一定是最小,且合法. 1 #include<cstdio> 2 int T,G,L; 3 int main() 4 { 5 scanf("%d",&T); 6 while(T--) 7 { 8 scanf("%d%d"

UVA 272 TEX Quotes 题解

//刚看刘汝佳的第二版紫书 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <string> 10 #inc

uva 1476 Error Curves 题解

题意:给n个二次函数f(x),定义F(x)=max(f(x)),即n个二次函数中的最大值.求F(x)在区间[1,1000]内的最小值. 根据题意可以知道,F(x)是单峰函数.于是我们可以三分解决.对于区间[L,R],找它的三等分点M1,M2,如果F(M1)<F(M2),则答案在[L,M2],否则在[M1,R]. 精度最好高一点..只差一两个数量级是不行的,因为有函数会放大误差.. 1 #include<cstdio> 2 #include<algorithm> 3 const

UVa 818 Cutting Chains 题解

难度:β 建议用时:40 min 这题应该有迭代加深搜索的解法的,但我参考网友做法,用暴力枚举法. 大致思路是:枚举圆环的每种开闭状态,统计符合要求的最小的打开的圆环的数量. 要判断打开圆环的某一种方法是否符合要求,容易想到的一个是先判断除去这些已打开的圆环外的闭合圆环有没有组成一个环. 如果还有环,那么无论把打开的圆环怎样重新连城一条链套回去,都不能消除环,而题目要求我们够一条链.所以如果任然存在环的方法是不行的. 0000   0 (此时还有一个环没打开,不能组成链) 0    0 0000