POJ 3504 HASH

题意

一堆字符串由许多个单词组成,但是除了单词的开始和结尾都做了一定程度的乱序。要求破解这个被打乱的句子。

题解

HASH+DP(暴力)。首先对单词进行处理,将单词去掉头和尾记录到头和尾组成的哈希表中。对于长度为1的单词特殊记录。然后进行暴力搜索(DP)。暴力搜索从0开始,0可能是从0开始到0-100区间内组成的任意一个的单词的字符(因为单词长度最大为100,这个需要特别注意,会不会TLE就看这个了)。于是我们便可以去针对每一个可能的字符串去哈希表里搜索,如果搜索到了那么就可以进行状态转移。
对于一个单词,可以状态转移到现有长度+单词长度的位置。因为涉及到是否存在模糊字符串的判断,因此在转移的时候需要分情况讨论。对于模糊的单词,状态转移之后的值应该为2。而对于非模糊的单词,则应该视情况而定,并且需要记录对应单词,因为非模糊单词是有可能组成最后结果的。
最后暴力搜索完以后,判断一下是否能形成合法答案,输出一下就可以了。

代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class Main{
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int ks=scanner.nextInt();
        Map<String, String> first[][]=new HashMap[30][30];
        Set<String> second[][]=new HashSet[30][30];
        for (int i = 0; i < 30; i++) {
            for (int j = 0; j < 30; j++) {
                first[i][j]=new HashMap<String,String>();
                second[i][j]=new HashSet<String>();
            }
        }
        while(ks!=0){
            boolean single[]=new boolean[30];
            String string=scanner.next();
            int len=string.length();
            ks--;
            int n=scanner.nextInt();
            for (int i = 0; i < 30; i++) {
                for (int j = 0; j < 30; j++) {
                    first[i][j].clear();
                    second[i][j].clear();
                }
            }
            for (int i = 0; i < n; i++) {
                String word=scanner.next();
                if(word.length()==1){
                    single[word.charAt(0)-'a']=true;
                }else{
                    int a=word.charAt(0)-'a';
                    int b=word.charAt(word.length()-1)-'a';
                    char arr[]=word.substring(1, word.length()-1).toCharArray();
                    Arrays.sort(arr);
                    String sortStr=String.valueOf(arr);
                    if(first[a][b].containsKey(sortStr)){
                        second[a][b].add(sortStr);
                    }else {
                        first[a][b].put(sortStr, word);
                    }
                }
            }
            int way[]=new int[1100];
            String pre[]=new String[1100];
            way[0]=1;
            for (int i = 0; i < len; i++) {
                if(way[i]>0){

                    if(single[string.charAt(i)-'a']){
                        way[i+1]=Math.min(way[i+1]+way[i],2);
                        pre[i+1]=String.valueOf(string.charAt(i));
                    }
                    for (int j = i+2; j <= len&&(j-i)<=100; j++) {
                        int a=string.charAt(i)-'a';
                        int b=string.charAt(j-1)-'a';
                        String word=string.substring(i+1, j-1);
                        char arr[]=word.toCharArray();
                        Arrays.sort(arr);
                        String sortStr=String.valueOf(arr);
                        if(second[a][b].contains(sortStr)){
                            way[j]=Math.min(way[j]+2*way[i],2);
                        }else if(first[a][b].containsKey(sortStr)){
                            way[j]=Math.min(way[j]+way[i],2);
                            pre[j]=first[a][b].get(sortStr);
                        }
                    }
                }
            }
            if(way[len]==2){
                System.out.println("ambiguous");
            }else if(way[len]==0){
                System.out.println("impossible");
            }else {
                List<String> ans=new ArrayList<String>();
                for(int i=len;i>0;i-=pre[i].length()){
                    ans.add(pre[i]);
                }
                Collections.reverse(ans);
                for (int i = 0; i < ans.size(); i++) {
                    if(i!=0)
                        System.out.print(" ");
                    System.out.print(ans.get(i));
                }
                System.out.println();
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值