题意:输入n组数a->b,再输入一串数字,其中数字可由a变换为b,求存在多少种情况。
思路:可转化为一个最短路径问题。将10个数字的变换情况分别看作一个节点,利用floyd求出所有通路,统计每种数的变换可能,再转化为组合问题。
注意点:求组合时要考虑溢出的可能。用大数乘法。
以下为AC代码:
评测状态 | Accepted |
题目 | P1129 产生数 |
递交时间 | 2014-11-06 17:14:05 |
代码语言 | C++ |
评测机 | VijosEx |
消耗时间 | 15 ms |
消耗内存 | 280 KiB |
评测时间 | 2014-11-06 17:14:07 |
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <deque>
#include <list>
#include <cctype>
#include <algorithm>
#include <climits>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <iomanip>
#include <cstdlib>
#include <ctime>
using namespace std;
struct node
{
char a;
char b;
friend bool operator < ( const node &a, const node &b )
{
return a.b < b.b;
}
} p[20];
bool adj[10][10];
int ans[50];
void muti ( int m )
{
int tmp = 0;
for ( int i = 0; i < 50; i ++ )
{
tmp = ans[i] * m + tmp;
ans[i] = tmp % 10000;
tmp = tmp / 10000;
}
}
void floyd ( int n )
{
for ( int i = 0; i < n; i ++ )
{
adj[i][i] = true;
for ( int j = 0; j < n; j ++ )
{
for ( int k = 0; k < n; k ++ )
{
if ( adj[j][i] && adj[i][k] )
{
adj[j][k] = true;
}
}
}
}
}
int main()
{
int num[15] = { 0 };
string str;
while ( cin >> str )
{
int n;
cin >> n;
memset ( adj, 0, sizeof ( adj ) );
memset ( ans, 0, sizeof ( ans ) );
for ( int i = 0; i < n; i ++ )
{
cin.clear();
cin >> p[i].a;
cin.clear();
cin >> p[i].b;
adj[p[i].a-'0'][p[i].b-'0'] = true;
}
floyd( 10 );
for ( int i = 0; i < 10; i ++ )
{
num[i] = 0;
for ( int j = 0; j < 10; j ++ )
{
if ( adj[i][j] )
{
num[i] ++;
}
}
}
ans[0] = 1;
for ( int i = 0; i < (int)str.size(); i ++ )
{
muti ( num[str[i] - '0'] );
}
int k;
for ( k = 49; k >= 0 && ans[k] == 0; k -- );
printf ( "%d", ans[k] );
k --;
for ( ; k >= 0; k -- )
{
printf ( "%04d", ans[k] );
}
cout << endl;
}
return 0;
}