NOIP2004 蟲食算C 預處理剪枝

2021-08-25 02:25:42 字數 3381 閱讀 1059

總時間限制:

1000ms

記憶體限制:

65536kb

題目

描述

所謂蟲食算,就是原先的算式中有一部分被蟲子啃掉了,需要我們根據剩下的數字來判定被啃掉的字母。來看乙個簡單的例子:

43#98650#45

+   8468#6633

---------------------------------    

44445506978

其中#號代表被蟲子啃掉的數字。

根據算式,我們很容易判斷:第一行的兩個數字分別是5和3,第二行的數字是5。

現在,我們對問題做兩個限制:

首先,我們只考慮加法的蟲食算。這裡的加法是n進製加法,算式中三個數都有n位,允許有前導的0。

其次,蟲子把所有的數都啃光了,我們只知道哪些數字是相同的,我們將相同的數字用相同的字母表示,不同的數字用不同的字母表示。

如果這個算式是n進製的,我們就取英文本母表午的前n個大寫字母來表示這個算式中的0到n-1這n個不同的數字:但是這n個字母並不一定順序地代表0到n-1)。

輸入資料保證n個字母分別至少出現一次。

badc

+ cbda

--------------------------

dccc

上面的算式是乙個4進製的算式。很顯然,我們只要讓abcd分別代表0123,便可以讓這個式子成立了。

你的任務是,對於給定的n進製加法算式,求出n個不同的字母分別代表的數字,使得該加法算式成立。輸入資料保證有且僅有一組解。

輸入

輸入檔案alpha.in包含4行。第一行有乙個正整數n(n<=26),後面的3行每行有乙個由大寫字母組成的字串,分別代表兩個加數以及和。這3個字串左右兩端都沒有空格,從高位到低位,並且恰好有n位。

輸出

輸出檔案alpha.out包含一行。在這一行中,應當包含唯一的那組解。解是這樣表示的:輸出n個數字,分別表示a,b,c……所代表的數字,相鄰的兩個數字用乙個空格隔開,不能有多餘的空格。

樣例輸入

5

abced

bdace

ebbaa

樣例輸出

1 0 3 4 2

【資料規模】

對於30%的資料,保證有n≤10;

對於50%的資料,保證有n≤15;

對於全部的資料,保證有n≤26。

題目解析

剛看此題時,第一想法是暴力列舉,即用全排列乙個乙個填數。而對應的時間複雜度是o(n!)

而最大的n可以取到26,所以必須剪枝,不然1000ms絕對超時

先看題目的舉例

…badc

而在填等式時,若從小的數開始倒著填,那麼最高位一定是先填最大的數,但若是這樣,最高位必定會進製,而題目說得清楚,都是相同的位數,所以若是這樣,也要在填完所有數之後才能發現最高位進製的填數錯誤,這樣和正著填有什麼區別。

因此,倒著填時,應從大的數字開始填起,這樣才能最大化剪枝

剪枝要點二

填數時從大的數字倒著往前填

若在填完數字後,再用一次高精度進行運算,那麼有那麼多種填數情況,肯定會超時。

其實,這裡只需儲存下上一位的進製,然後一位一位地進行檢驗即可,這樣便少了陣列的轉換

剪枝要點三

填完數後只需按位相加,與和數進行檢測

**實現

#include

#include

#include

#define maxn 100

char a[maxn]

,b[maxn]

,c[maxn]

;bool used[maxn]

;//在ready()預處理函式中,記錄這個字母是否在之前的位數中出現過

char rlist[maxn]

;//剪枝要點一中的字母出現順序表

int num[maxn]

;//以字母ascii碼作為下標,表示該字元的數值

int tot;

//記錄rlist陣列的下標

int n;

//n進製

void

ready()

//剪枝一 預處理函式

//之後的b,c都是如此if(

!used[b[i]])

if(!used[c[i]])

}memset

(used,0,

sizeof

(used));

//重置陣列,方便在dfs中使用

memset

(num,-1

,sizeof

(num));

//將儲存數值的陣列置為-1,-1表示沒有被賦值,即不知道值

return;}

bool

check()

//檢測填的數字是否合適

if(num[a[i]]!=

-1&& num[b[i]]!=

-1&& num[c[i]]==

-1)//情況二 知道兩個加數而不知道和

if(num[a[i]]!=

-1&& num[b[i]]==

-1&& num[c[i]]!=

-1)//情況三 知道其中的a加數與和

if(num[a[i]]==

-1&& num[b[i]]!=

-1&& num[c[i]]!=

-1)//情況四 知道其中的b加數與和

}//若都可以,說明填數正確 返回1

return1;

}boolok(

)//檢測最終的填數是否正確

//若最後還有進製 說明最終結果不止n位 與題意不符 返回0

if(x)

return0;

//若成立 說明等式正確 返回1

return1;

}void

print()

//輸出最終結果

void

dfs(

int x)

//x控制rlist的下標,表示正在填rlist[i]的值

return

;//如果不正確,回溯回去,繼續尋找正確填法

}else

//如果填數沒有完成

dfs(x+1)

;//進入深搜

used[i]=0

; num[rlist[x]]=

-1;//還原現場}}

}int

main()

NOIP2004 蟲食算 搜尋

問題描述 所謂蟲食算,就是原先的算式中有一部分被蟲子啃掉了,需要我們根據剩下的數字來判定被啃掉的字母。來看乙個簡單的例子 43 9865 045 8468 6633 44445506978 其中 號代表被蟲子啃掉的數字。根據算式,我們很容易判斷 第一行的兩個數字分別是5和3,第二行的數字是5。現在,...

noip2004蟲食算 搜尋

首先這題標算據說是高斯消元,但標籤已經是搜尋了。身為蒟蒻當然只會打搜尋。而我的搜尋又打的很翔,從右到左dfs搜過來,暴枚這一列三個數的情況,然後進製。注意列舉從大到小枚,因為第一位 最左邊 不會進製,所以從右到左時從大到小會更好,不然會被卡tle乙個點。luogu judger enable o2 ...

NOIP2004提高組 蟲食算

所謂蟲食算,就是原先的算式中有一部分被蟲子啃掉了,需要我們根據剩下的數字來判定被啃掉的字母。來看乙個簡單的例子 43 9865 045 8468 6633 44445509678 其中 號代表被蟲子啃掉的數字。根據算式,我們很容易判斷 第一行的兩個數字分別是5和3,第二行的數字是5。現在,我們對問題...