UVA - 11604 General Sultan(构图暴力)

题目大意:给出n个字符串(01串),问是否存在一个二进制序列,存在至少两种编码方式

比如{a = 01011111, b = 0101, c = 1111010, d = 010}

二进制序列01011111010就有两种编码方式了,可以由a+d组成,也可以由b+c+d组成(注意这里的二进制序列不是指所给的武器的二进制序列,刚开始没理解。。被坑了)

解题思路:这样就比较好理解了,字符串匹配,不断的匹配

首先为每个字符都构建一个点,那怎么连边呢?

找匹配的部分进行连边,假设有两个字符串i,j,现在从字符串i的s位置往后开始和字符串j开始匹配,那么就有四种匹配结果了(以下的i字符串均指s位置后面的字符部分,id[i][j]指字符串i的第j个字符串的点标记,从0开始)

  1. 两个字符串都刚好匹配完了,那就表明字符串i从s位置往后可以由j字符串组成,说明字符串i如果能匹配到s,那么就必然能匹配完,所以可以将id[i][s]这个点连向终点了
  2. i字符串没匹配完,j字符串匹配完了,那么下一个点就是从id[i][s+字符串j的长度]匹配了,所以id[i][s] 和id[i][i+字符串j的长度]连边
  3. j字符串没匹配完,i字符串匹配完了,那么下一个匹配点就是j字符串和i字符串匹配的结束位置+1,所以id[i][s]和id[j][匹配结束位置]连边
  4. 两个字符串都没有匹配完,那么就不会重了

现在的问题就转化成了,从任意一个字符串的起点出发,如果能走到终点的话,就表明存在字符串有两种编码方式

如果不太理解的话,可以画字符串的四种匹配情况的图

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 110
#define L 25
#define M 2500
#define S 250010

struct Edge {
    int to, next;
}E[S];

int n, End, tot;
int id[N][L], head[M], len[N];
char weapon[N][L];
bool vis[M];

void AddEdge(int u, int v) {
    E[tot].to = v;
    E[tot].next = head[u];
    head[u] = tot++;
}

void init() {
    memset(head, -1, sizeof(head));
    tot = 0;

    int k = 0;
    for (int i = 1; i <= n; i++) {
        scanf("%s%s", weapon[i], weapon[i]);
        len[i] = strlen(weapon[i]);
        for (int j = 0; j < len[i]; j++)
            id[i][j] = k++;
    }
    End = k;

    for (int i = 1; i <= n; i++)
         for (int s = 0; s <= len[i]; s++)
             for (int j = 1; j <= n; j++) {
                 if (i == j)
                     continue;
                 int t = 0;
                 for (t = 0; t <= len[j] && s + t <= len[i]; t++)
                     if (weapon[i][s + t] != weapon[j][t])
                         break;
                 if (t >= len[j] && s + t >= len[i])
                     AddEdge(id[i][s], End);
                 else if(t >= len[j])
                     AddEdge(id[i][s], id[i][s + t]);
                 else if(s + t >= len[i])
                     AddEdge(id[i][s], id[j][t]);
             }
}

bool flag;

void dfs(int u) {
    if (u == End) {
        flag = true;
        return;
    }

    vis[u] = true;
    for (int i = head[u]; i != -1; i = E[i].next) {
        int v = E[i].to;
        if (!vis[v])
            dfs(v);
        if (flag)
            return ;
    }
}

int cas = 1;
void solve() {
    memset(vis, 0, sizeof(vis));
    flag = false;
    for (int i = 1; i <= n; i++) {
        if (!vis[id[i][0]])
            dfs(id[i][0]);
        if (flag) break;
    }
    if (!flag)
        printf("Case #%d: Not ambiguous.\n", cas++);
    else
        printf("Case #%d: Ambiguous.\n", cas++);

}

int main() {
    while (scanf("%d", &n) != EOF && n) {
        init();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-20 14:56:44

UVA - 11604 General Sultan(构图暴力)的相关文章

UVA - 11604 General Sultan 题解

题目大意: 有若干模式串,将某些模式串拼接起来(一个可以使用多次)形成一个长模式串,判断能否有两种或更多种不同的拼法拼成相同的模式串. 思路: 神奇的构图,暴力的求解. 可以发现,若有不同的拼法,则一个模式串的前缀要与一个模式串的后缀相同. 因此我们就将问题转化成:从两个模式串开始,不停的按照前后缀匹配,最后达到两个串同时在一个点结束. 那么,将每一个串的每一个字符都看作一个点,n2len2暴力枚举i串从z开始的后缀和j串(自己也可以,但不能让前缀是其本身)的前缀做匹配,看是否能将其中一个串匹配

【UVA】12169-Disgruntled Judge(暴力or欧几里得)

可能由于后台数据的原因,这道题直接暴力枚举a,b进行判断也能过,不过跑的时间长,效率太差了. 14021006 12169 Disgruntled Judge Accepted C++ 0.876 2014-08-11 08:46:28 不说了,比较无脑. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #incl

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 10825 - Anagram and Multiplication(暴力)

题目链接:uva 10825 - Anagram and Multiplication 题目大意:给出m和n,要求找一个m位的n进制数,要求说该数乘以2~m中的任意一个数的结果是原先数各个位上数值的一个排序. 解题思路:枚举最后一位数,然后用这个数去乘以2~m并对n取模,然后得到的数一定就是这个数的组成,暴力搜索一下并判断. #include <cstdio> #include <cstring> #include <algorithm> using namespace

uva 11256 - Repetitive Multiple(gcd+暴力)

题目链接:uva 11256 - Repetitive Multiple 题目大意:给定一个数n,要求找到最小的k,使得k?n为题目中定义的重复数字. 解题思路:枚举k?n的循环节长度,比如当前枚举为2,那么一次判断u=1001,1001001,1001001001 ...,取d = gcd(n,u), 那么k = u / d, a = n / d (因为n?k=u?a)并且保证a的长度为2,所以k和a要同时扩大相应倍数.枚举过程中为何k. #include <cstdio> #include

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 646 - The Gourmet Club(暴力)

题目链接:uva 646 - The Gourmet Club 题目大意:有16个人参加聚会,聚会一共5天,每天有4桌,每桌4个人,一起吃饭的4个人会互相认识.现在要安排座位使得16个任意两个人都互相认识.给出前三天的安排,求后两天的安排. 解题思路:任意两个人之间肯定只能同桌一次.所以根据这个条件,只要枚举出第4天的第1桌的情况,就可推导出所有的,或者是矛盾. 在Poj和Zoj上都过了,uva上过不了,求大神指教. #include <stdio.h> #include <string

UVa 11210 Chinese Mahjong (暴力,递归寻找)

题意:这个题意.有点麻烦,就是说给定13张牌,让你求能“听”的牌.(具体的见原题) 原题链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2151 析:看到这个题,真是麻烦啊,我又不懂麻将,看了好久才明白什么是“听”.分析一下思路. 首先对所有的牌都进行编号,然后暴力,首先的是先判断是哪个是将,然后再进一步判断, 哪一个是刻子,和顺子

uva 140 Bandwidth (全排列+暴力枚举)

uva 140 Bandwidth Given a graph (V,E) where V is a set of nodes and E is a set of arcs in VxV, and an ordering on the elements in V, then the bandwidth of a node v is defined as the maximum distance in the ordering between v and any node to which it