题意:
给定n个字符串,从a到j,把数字0到9一一映射到字母,求问字符串对应的数字总和最小是多少。
注意没有前导零,即便字符串只有一个字母,也不能映射为零。(这里WA了5次...)
分析:贪心,统计每个字母在每一位出现的个数。因为有10个字母,所以把字母出现个数看成10进制的数处理。从高位到低位逐一比较,高位出现次数越少的字母映射的数字越小。映射为0的字母必须没有出现在任何一个字符串的首位。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 1000+10;
const int maxm = 20;
int n;
char str[maxn][10];
int num[30];
struct node{
int id;
bool lead;
int cnt[maxm];
bool operator <(const node &rhs) const {
for (int i=maxm-1; i>=0; i--)
if (cnt[i]!=rhs.cnt[i]) return cnt[i]<rhs.cnt[i];
return 0;
}
}a[30];
void init(){
for (int i=0; i<26; i++) {
a[i].id = i;
a[i].lead = 0;
memset(a[i].cnt,0,sizeof(a[i].cnt));
}
}
void solve(){
int k = 9;
for (int i=0; i<10; i++) num[a[i].id] = k--;
k = 9;
while (k && a[k].lead) {swap(num[a[k].id],num[a[k-1].id]); k--;}
LL ans = 0,sum;
int sz;
for (int i=0; i<n; i++) {
sz = strlen(str[i]);
sum = 0;
for (int k=0; k<sz; k++) sum = sum*10 + num[str[i][k]-'a'];
ans += sum;
}
printf("%I64d\n",ans);
}
int main(){
int sz,j;
while (scanf("%d",&n)==1){
init();
for (int i=0; i<n; i++) {
scanf("%s",str[i]);
sz = strlen(str[i]);
a[str[i][0]-'a'].lead = 1;
for (int k=0; k<sz; k++) {
j = str[i][sz-k-1]-'a';
a[j].cnt[k]++;
}
}
for (int i=0; i<10; i++) {
for (int k=0; k<maxm-1; k++) {
a[i].cnt[k+1] += a[i].cnt[k]/10;
a[i].cnt[k] %= 10;
}
}
sort(a,a+10);
solve();
}
return 0;
}