算法提高 產生數
給出一個整數 n(n<10^30) 和 k 個變換規則(k<=15)。
規則:
一位數可變換成另一個一位數:
規則的右部不能爲零。
例如:n=234。有規則(k=2):
2-> 5
3-> 6
上面的整數 234 經過變換後可能產生出的整數爲(包括原數):
234
534
264
564
共 4 種不同的產生數
問題:
給出一個整數 n 和 k 個規則。
求出:
經過任意次的變換(0次或多次),能產生出多少個不同整數。
僅要求輸出個數。
輸入格式:
n k
x1 y1
x2 y2
… …
xn yn
輸出格式:
一個整數(滿足條件的個數)
輸入樣例:
在這裏給出一組輸入。例如:
234 2
2 5
3 6
輸出樣例:
在這裏給出相應的輸出。例如:
4
方法:
這道題費了不少時間,這道題有好幾個坑,開始我只考慮了X,X位置的數一共有多少個Y,一直不能全部通過,後發現Y也能作爲X,舉個例子:
輸入的是
1234 3
2 3
3 2
3 5
這個並不是有6種,答案應該爲9。2可以變爲3,3可以變爲2、5,但是第二個數變成3後要可以變成2和5,即第二個數有2、3、5三種可能,第三個數有2、3、5三種可能,即答案爲9。這是第一個注意的地方
還有一個需要注意的地方,最後的結果是一個很大的數,我用了long long都不能滿足,最後只能用字符串存這個數。
這個題我是把這個字符串轉換爲字符串數組,滿足條件就在這個字符串後面加入這個字符。以題目爲例
234 2
2 5
3 6
234轉換爲長度爲3的字符串數組
2
3
4
2->5,5不和2這個字符串任何字符重複,插入5,變成
25
3
4
3->6,6不和3這個字符串任何字符重複,插入6,變成
25
36
4
最後結果就是每個字符串長度的乘積。
代碼:
#include<vector>
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
struct num//用結構體存變換的X、Y
{
char x;
char y;
};
int main()
{
string n;
int x,flag1=1,flag2=1,carry,t;
vector<int>cnt;//最後的結果
cnt.push_back(1);
cin >> n >> x;
vector<num>arr(x);
vector<string>nn(n.length());//轉換爲字符串數組
for (int i = 0; i < n.length(); i++)
{
nn[i] += n[i];
}
for (int i = 0; i < x; i++)
{
cin >> arr[i].x >> arr[i].y;
}
for (int m = 0; m < x; m++)//每次循環都要從遍歷所有的X、Y的變換,因爲Y也能作爲X變換
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < nn.size(); j++)
{
flag1 = 1; flag2 = 1;
for (int k = 0; k < nn[j].length(); k++)
{
if (arr[i].x == nn[j][k])
{
flag1 = 0;
}
if (arr[i].y == nn[j][k])
{
flag2 = 0;
}
}
if (flag1 == 0 && flag2 == 1)//變換的X要在這個字符串的字符中且Y不在字符中
{
nn[j] += arr[i].y;
}
}
}
}
for (int i = 0; i < nn.size(); i++)//乘法運算
{
carry = 0;//進位
for (int j = cnt.size() - 1; j >= 0; j--)
{
t = cnt[j];
cnt[j] = (cnt[j] * nn[i].length() + carry) % 10;//每一位做乘法後的值
carry = (t * nn[i].length() + carry) / 10;//進位位的值
}
if (carry != 0)
{
while (carry >= 1)//!!!!要把進位位分割成每一位存進數組
{
cnt.insert(cnt.begin() + 0, carry % 10);//(在數組的第0位插入,即數組最前面)
carry = carry / 10;
}
}
}
for (int i = 0; i < cnt.size(); i++)
{
cout << cnt[i];
}
return 0;
}