UVa 10132 - File Fragmentation 贪心+枚举

/**
 * 贪心题
 * 思路:能否先找出所有可能的答案? 如果能找出所有可能的答案而且可能的情况很小的话,一一枚举也是很快的!
 * 怎么找?  首先在每次输入的时候,就对所有字符串进行预处理。 用三维数组str来存数据,第一个方括号表示的是该字符串的长度,
 * 中间的表示有2个这样长度的字符串(为什么只有2个,因为按照题意,必然是能够够成原文件的,同样长度的字符串,
 * 只有可能是前面那半和后面那半两种可能。 这样在每次输入的时候就可以判断,如果相同的话就不存入数组,不同的话就存。
 * 再然后就是找可能的答案,首先先找到最小长度和最大长度的字符串,因为这两种必能且只能是这两一起匹配成原文件!
 * 所以如果说最小字符串有两个 a, b 那最大字符串必有2个c, d 那可能的答案只能是ab, ac, ba, bc
 * 如果最小字符串只有一个,那更简单了, 只有可能是ab 或者 ba
 * 这样就构造了可能的解空间,而且易正明肯定是完整的,也就是不会漏解
 * 之后再找下一个适合的两种长度la, lb可以构造出原文件的,但注意la + lb 要等于 之前的最小长度加最大长度。
 * 然后再根据之前的构造所有可能的情况与解空间对比,一样的那个就是原文件了!
 *
 *   这里最最关键的是,就是按照自己的算法写的时候, 一开始一直RE,我还以为数组不够大,一直改还是RE
 *   找了好久才发现,忽略了一种当两种长度都相等的时候,也就是最小长度 等于 最大长度的时候! 而且,这个时候的两种字符串是相同的还是不同的!!
 */

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
bool vis[300];
char anss[5][300];
char str[300][2][300];
int minLen, maxLen;

int gotAns() {
    int i, secMin = minLen + 1, secMax = maxLen - 1;
    for(i = secMin; i < 300; i ++) {
        if(str[i][0][0] != '*') {
            secMin = i;
            break;
        }
    }
    secMax = maxLen - (secMin - minLen);
    char curAns[300];
    for(i = 0; i < 4; i ++) {

        strcpy(curAns, str[secMin][0]);
        strcat(curAns, str[secMax][0]);
        if(!strcmp(curAns, anss[i])) break;
        if(str[secMin][1][0] != '*') {
            strcpy(curAns, str[secMin][0]);
            strcat(curAns, str[secMax][1]);
            if(!strcmp(curAns, anss[i])) break;

            strcpy(curAns, str[secMax][0]);
            strcat(curAns, str[secMin][0]);
            if(!strcmp(curAns, anss[i])) break;

            strcpy(curAns, str[secMax][1]);
            strcat(curAns, str[secMin][0]);
            if(!strcmp(curAns, anss[i])) break;
        } else {
            strcpy(curAns, str[secMax][0]);
            strcat(curAns, str[secMin][0]);
            if(!strcmp(curAns, anss[i])) break;
        }
    }

    return i;
}

void makeAns() {
    strcpy(anss[0], str[minLen][0]);
    strcat(anss[0], str[maxLen][0]);
    if(str[maxLen][1][0] == '*') {
        strcpy(anss[1], str[maxLen][0]);
        strcat(anss[1], str[minLen][0]);
    } else {
        strcpy(anss[1], str[minLen][0]);
        strcat(anss[1], str[maxLen][1]);

        strcpy(anss[2], str[maxLen][0]);
        strcat(anss[2], str[minLen][0]);

        strcpy(anss[3], str[maxLen][1]);
        strcat(anss[3], str[minLen][0]);
    }
}

int main()
{
    //freopen("in.txt", "r", stdin);
    int n;
    char cur[300];
    scanf("%d", &n);
    getchar();
    for(int i = 0; i < n; i ++) {
        int len;
        if(i != 0) printf("\n");
        else getchar();
        memset(str, '*', sizeof(str));
        memset(vis, false, sizeof(vis));
        while(gets(cur) != NULL) {
            if(!strcmp(cur, "")) break;
            len = strlen(cur);
            if(str[len][0][0] == '*') {
                strcpy(str[len][0], cur);
            } else if(strcmp(cur, str[len][0]) != 0) {
                strcpy(str[len][1], cur);
            }
            int l, r;
            for(l = 0; l < 300; l ++) {
                if(str[l][0][0] != '*') {
                    minLen = l;
                    break;
                }
            }
            for(r = 299; r >= 0; r --) {
                if(str[r][0][0] != '*') {
                    maxLen = r;
                    break;
                }
            }
        }
        if(maxLen == minLen) {
            strcpy(cur, str[maxLen][0]);
            if(str[maxLen][1][0] != '*')
                strcat(cur, str[maxLen][1]);
            else
                strcat(cur, str[maxLen][0]);
            puts(cur);
            continue;
        }

        makeAns();
        puts(anss[gotAns()]);
    }

    return 0 ;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值