Page 4 of 4
Re: 843 - Crypt Kicker
Posted: Wed Aug 14, 2013 11:57 pm
by brianfry713
Yes usually there is a newline right before EOF but I wouldn't count on it.
Try simplifying your code as I described before. Also try changing your input parsing to just use C I/O. I only used scanf, getchar, gets, and printf in my AC code, no cin.
Crypt Kicker Judging Problem
Posted: Tue Oct 29, 2013 1:53 pm
by saadtaame
Is the judge misjudging the problem crypt kicker, i've tested my solution over and over but the judge keeps telling me its wrong, I even copied a correct solution and submitted it but still wrong answer. Here is my solution. If you can test my solution or find a problem with it please do.
Code: Select all
#include <stdio.h>
#include <string.h>
typedef char word[17];
word dict[1001];
word words[100];
char line[81];
char linep[81];
char map[26], mapinv[26];
int at[17], count[17];
int n, i, j, len1, len2, letters_line;
int backtrack, nwords_line, solution;
char * cp;
int cmp(const void * x, const void * y)
{
return (strlen((char *)x)-strlen((char *)y));
}
int count_letters(char * L)
{
int l[26], c=0, k;
char * cp = L;
memset(l, 0, sizeof(int)*26);
for(; *cp; cp++)
{
if(*cp == ' ') continue;
l[*cp -'a']=1;
}
for(k=0;k<26;k++) if(l[k])c++;
return c;
}
void print_stars()
{
char * cp = linep;
for(;*cp; cp++)
{
if(*cp == ' ') printf(" ");
else printf("*");
}
printf("\n");
}
int is_solution(char * m, char * minv)
{
int x = 0, y;
for(y=0;y<26;y++)
{
if(!m[y]) continue;
x++;
}
return x==letters_line;
}
void process_solution(char * m, char * minv)
{
char * cp = linep;
for(;*cp;cp++)
{
if(*cp == ' ') printf(" ");
else printf("%c", minv[*cp-'a']);
}
printf("\n");
}
int done;
void search(int k, char * m, char * minv)
{
char m_[26], minv_[26];
int I, J, LEN;
if(done || k>nwords_line+1) return;
if(is_solution(m, minv))
{
process_solution(m, minv);
done=solution=1;
}
else
{
LEN = strlen(words[k]);
for(I=at[LEN];I<at[LEN]+count[LEN];I++)
{
memcpy(m_, m, 26*sizeof(char));
memcpy(minv_, minv, 26*sizeof(char));
backtrack = 0;
for(J=0;J<LEN;J++)
{
if(!m_[dict[I][J]-'a'])
{
m_[dict[I][J]-'a'] = words[k][J];
minv_[words[k][J]-'a'] = dict[I][J];
}
else if(m_[dict[I][J]-'a'] != words[k][J])
{
backtrack=1; break;
}
}
if(!backtrack) search(k+1, m_, minv_);
}
}
}
int empty(char * x)
{
char * c = x;
for(; *c; c++) if(*c != ' ' && *c != '\n') return 0;
return 1;
}
int main()
{
for(i = 0; i < 17; i++) { at[i] = 0; count[i] = 0; }
scanf("%d\n", &n);
for(i = 1; i <= n; i++) { scanf("%s\n", dict[i]); count[strlen(dict[i])]++; }
qsort(dict+1, n, sizeof(word), cmp);
len1 = strlen(dict[1]); at[len1] = 1;
for(i = 2; i <= n; i++)
{
len2 = strlen(dict[i]);
if(len1==len2) continue;
at[len2] = i; len1 = len2;
}
while(fgets(line, 81, stdin))
{
if(empty(line)) continue;
len1 = strlen(line);
if(line[len1-1]=='\n') line[len1-1]='\0';
done=solution=0;
memset(map, 0, 26*sizeof(char));
memset(mapinv, 0, 26*sizeof(char));
letters_line = count_letters(line);
strcpy(linep, line);
nwords_line = 2;
cp = strtok(line, " ");
strcpy(words[1], cp);
while((cp=strtok(0, " "))) strcpy(words[nwords_line++], cp);
strcpy(words[nwords_line], "");
nwords_line--;
search(1, map, mapinv);
if(!solution) print_stars();
}
return 0;
}
Re: Crypt Kicker Judging Problem
Posted: Tue Oct 29, 2013 10:18 pm
by brianfry713
On problem 843, if there is a blank line in the output, my AC code would print that line and any spaces it had to the output.
Re: Crypt Kicker Judging Problem
Posted: Wed Oct 30, 2013 10:46 pm
by saadtaame
I figured out the problem. I was using the globals map, mapinv where I should have been using the locals m_, minv_ in the funciton search. It got accepted.
Crypt Kicker :Mis_Judging
Posted: Tue Sep 30, 2014 5:31 pm
by fresher96
Mr.
saadtaame
you ignored part of the problem description it says
To ensure that the encryption is reversible, no two letters are
replaced by the same letter.
adding this to your "is_solution()" function you would get AC
Code: Select all
int QW;
for(y=0;y<26;y++)
for(QW=0;QW<26;QW++)
if(QW != y && m[QW] != '\0' && m[y] != '\0' && m[QW] == m[y])
return 0;
Master
brianfry713
i think there is another problem with the judge
for the program written by
saadtaame
after fixing
the judge accepted it but it's wrong try the input
the previous program prints
but it's wrong because "dna" isn't mentioned in the dictionary
and the output should be
you can check it in your
http://www.udebug.com/UVa/843
Re: 843 - Crypt Kicker
Posted: Tue Sep 30, 2014 9:19 pm
by brianfry713
I don't have access to the judge's I/O.
If the judge accepts wrong code it doesn't really mean that there is a problem with it, just that it doesn't test that case.
Re: 843 - Crypt Kicker
Posted: Sun Aug 19, 2018 12:45 pm
by Maged_Saeed
Hi everyone
I am really stuck in this problem. I did a Java solution for it. The code seems non erroneous passing the test cases proposed by uDebug site. However, I got WA verdict on the uva. Can anyone identify the problem in the code?
Here is the code:
Code: Select all
import java.util.*;
public class P843 {
public static void main(String[] args) {
Scanner c = new Scanner(System.in);
int dictionarySize = c.nextInt();
c.nextLine();
// get the dictionary from the input stream:
String[] words = new String[dictionarySize];
for (int i = 0; i < words.length; i++)
words[i] = c.nextLine();
// get encrypted input
String line = c.nextLine();
while (c.hasNextLine() && line.trim().length() > 0) {
String[] eWords = line.split(" ");
String[] dWords = decryptWords(eWords, words);
for (int i = 0; i < dWords.length; i++)
if (i != dWords.length - 1) {
System.out.print(dWords[i] + " ");
} else {
System.out.println(dWords[i]);
}
line = c.nextLine();
if (line.trim().length() == 0)
System.exit(0);
}
}
private static String[] decryptWords(String[] eWords, String[] words) {
String[] dWords = new String[eWords.length];
// get copy of the dWords so that the original version not destroyed
String[] eWordsCopy = Arrays.copyOf(eWords, eWords.length);
// sort by length from the greatest to the smallest
Arrays.sort(eWordsCopy, new Comparator<String>() {
@Override
public int compare(String w1, String w2) {
return Integer.compare(w2.length(), w1.length());
}
});
// initialize a key array to hold decrypted letters:
char[][] keyArray = new char[2][26];
for (int i = 0; i < 26; i++) {
keyArray[0][i] = (char) ('a' + i);
keyArray[1][i] = '*';
}
// restore keyArray original values if there is no solution to all words
if (!matchWords(words, eWordsCopy, keyArray))
for (int i = 0; i < 26; i++) {
keyArray[0][i] = (char) ('a' + i);
keyArray[1][i] = '*';
}
for (int i = 0; i < eWords.length; i++) {
StringBuilder temp = new StringBuilder();
for (int j = 0; j < eWords[i].length(); j++)
temp.append(keyArray[1][eWords[i].charAt(j) - 97]);
dWords[i] = temp.toString();
}
return dWords;
}
private static boolean matchWords(String[] words, String[] eWords, char[][] keyArray) {
ArrayList<String> promisingWords = new ArrayList<>();
String eWord = eWords[0];
// this is an array of booleans to check whether a letter got updated. This array is useful in the backtracking
// step where we remove a word from the keyArray
boolean[] updatePattern = new boolean[eWord.length()];
// get promising words that may match
for (String word : words)
if (word.length() == eWord.length()
&& wordPattern(word).equals(wordPattern(eWord)))
promisingWords.add(word);
for (String word : promisingWords) {
if (mapWord(eWord, word, keyArray, updatePattern)) {
if (eWords.length > 1) {
// recursive call:
if (matchWords(words, Arrays.copyOfRange(eWords, 1, eWords.length), keyArray))
return true;
else {
// remove the word from the dictionary to try another one
for (int i = 0; i < eWord.length(); i++)
if (keyArray[1][eWord.charAt(i) - 97] == word.charAt(i) && updatePattern[i])
keyArray[1][eWord.charAt(i) - 97] = '*';
}
}
// if there are now decrypted words, then return true
else
return true;
}
}
// if there is no word mapped, then return false
return false;
}
private static boolean mapWord(String eWord, String word, char[][] keyArray, boolean[] updatePattern) {
// check one-to-one from the decrypted word to the dictionary word:
for (int i = 0; i < eWord.length(); i++)
if (keyArray[1][eWord.charAt(i) - 97] != word.charAt(i)
&& keyArray[1][eWord.charAt(i) - 97] != '*')
return false;
// check the other way around
for(int i=0; i<word.length(); i++)
if(!isLetterMapped(eWord.charAt(i), word.charAt(i), keyArray))
return false;
// update the key array:
for(int i=0; i<eWord.length(); i++) {
if (keyArray[1][eWord.charAt(i) - 97] == word.charAt(i))
updatePattern[i] = false;
else {
keyArray[1][eWord.charAt(i) - 97] = word.charAt(i);
updatePattern[i] = true;
}
}
// System.out.println("eWord: " + eWord);
// System.out.println("word: " + word);
// System.out.println("this mapping is: " + isMapped);
// if (isMapped)
// for (char[] aKeyArray : keyArray) System.out.println(Arrays.toString(aKeyArray));
return true;
}
private static boolean isLetterMapped(char eLetter, char letter, char[][] keyArray) {
for (int i = 0; i < 26; i++)
if (keyArray[1][i] == letter && keyArray[0][i] != eLetter)
return false;
return true;
}
// generate a word pattern
private static String wordPattern(String word) {
if (word.length() > 0) {
StringBuilder mapped = new StringBuilder();
int count = 0;
HashMap<Character, Character> mapping = new HashMap<>();
for (int i = 0; i < word.length(); i++)
if (!mapping.containsKey(word.charAt(i)))
mapping.put(word.charAt(i), (char) (48 + count++));
for (int i = 0; i < word.length(); i++)
mapped.append(mapping.get(word.charAt(i)));
return mapped.toString();
} else {
return "";
}
}
}