信息學奧賽:1361:產生數(Produce)
我參考了這篇文章
1361:產生數(Produce)
時間限制: 1000 ms 內存限制: 65536 KB
提交數: 3270 通過數: 1402
【題目描述】
給出一個整數n(n≤2000)和k個變換規則(k≤15)。規則:
① 1個數字可以變換成另1個數字;
② 規則中,右邊的數字不能爲零。
例如:n=234,k=2規則爲
2 → 5
3 → 6
上面的整數234經過變換後可能產生出的整數爲(包括原數)234,534,264,564共4種不同的產生數。
求經過任意次的變換(0次或多次),能產生出多少個不同的整數。僅要求輸出不同整數個數。
【輸入】
nkx1x2…xny1y2…yn
【輸出】
格式爲一個整數(滿足條件的整數個數)。
【輸入樣例】
234
2
2 5
3 6
【輸出樣例】
4
思路:
1.這題一開始我理解錯了,我以爲在原數的基礎上只執行一次變換規則,我說這題還不簡單嘛,結果我又想這和隊列有什麼聯繫。後來參考網上的答案才理解這道題說的什麼意思。
2.一個數num可以把某一位變成另一個數,整個數num就變成了另一個新數num1,在新數num1的基礎上又可以把某一位變成另一個數,新數num1又會變成另一個新數num2…這樣想很麻煩。
3.其實我們只用知道原數num的每一位數有多少種變換,然後每一位的可能的變換數相乘即可。
4.所以問題就拆分爲一個一位數在k個變換規則的約束下有多少種變換,題目示例2->4 ,3->5。也就是234這個數的第一位2可以變成4,這一位存在兩種可能結果,同理第二位3也存在兩種可能結果。所以結果就是4=2*2。
5.如果變換規則是這樣的呢?2->3,3->4,3->5這就要用到隊列了,加上bfs的思想。
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 16; // 題目種的變換規則<=15
char num[5]; // 題目種的數<2000最多也就4位數,
int k;
int from[maxn], to[maxn]; // 存放變換規則
bool vis[maxn]; // 用來當作標記,訪問過的數不能再訪問了
long long ans = 1;
long long bfs() {
int len = strlen(num);
queue<int>q;
for (int i = 0; i < len; i++) { // 對num的每一位進行bfs
int now = num[i] - '0';
q.push(now);
memset(vis, true, sizeof(vis));
int temp = 1;
while (!q.empty()) {
int top = q.front();
for (int j = 0; j < k; j++) {
if (top == from[j] && vis[to[j]]) {
temp++;
q.push(to[j]);
vis[from[j]] = false; // 2->5 5->2
vis[to[j]] = false; // 2->5 3->5
}
}
q.pop();
}
ans *= temp;
}
return ans;
}
int main() {
cin >> num;
cin >> k;
for (int i = 0; i < k; i++)
cin >> from[i] >> to[i];
cout << bfs();
//getchar();
//getchar();
return 0;
}
// 看上面的那篇參考文章大佬隊列的實現方式可以借鑑借鑑,
int q[10001];
int head = 0, tail = 0;
q[tail++] = num; // 往隊列裏面壓一個數
num = q[head]; // 取一個數
head++; // 彈出一個數
基礎算法學習我一直認爲是見多識廣而不是獨立非把題做出來不可。因爲沒這麼多的時間。
看了別人的答案才知道隊列還有這樣的實現方式,bfs不單單是針對二維圖形的上下左右。