题意:给你N个车牌号(字符串),两个车牌号之间的distance为这两个编号之间不同字母的个数。一个编号只能由另一个编号“衍生”出来,代价是这两个编号之间相应的distance,现在要找出一个“衍生”方案,使得总代价最小,也就是distance之和最小。
思路:建图,然后跑prim或者建边跑kruskal。
prim:
//#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
const int MAXN = 2005;
const int INF = 0x3f3f3f3f;
int n, len, G[MAXN][MAXN];
//string str[MAXN];//会超时!!!
char str[MAXN][MAXN];
int check(char a[MAXN], char b[MAXN])
{
int ans = 0;
for (int i = 0; i < len; i++)
{
if (a[i] != b[i]) ans++;
}
return ans;
}
int prim()
{
bool vis[2005];
int dis[2005];
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; i++) dis[i] = G[0][i];
dis[0] = 0; vis[0] = true;
int ans = 0;
for (int i = 1; i < n; i++)
{
int MIN = INF, pos;
for (int j = 0; j < n; j++)
{
if (!vis[j] && dis[j] < MIN)
{
MIN = dis[j]; pos = j;
}
}
ans += MIN;
vis[pos] = true;
for (int j = 0; j < n; j++)
{
if (!vis[j] && dis[j] > G[pos][j])
{
dis[j] = G[pos][j];
}
}
}
return ans;
}
int main()
{
while (~scanf("%d", &n) && n)
{
cin.get();//读/n
for (int i = 0; i < n; i++) gets(str[i]);//cin >> str[i];
len = strlen(str[0]);//len = str[0].length();
for (int i = 0; i < n; i++)
{
G[i][i] = 0;
for (int j = i + 1; j < n; j++)
{
G[i][j] = G[j][i] = check(str[i], str[j]);
}
}
printf("The highest possible quality is 1/%d.\n", prim());
}
return 0;
}
/*
4
aaaaaaa
baaaaaa
abaaaaa
aabaaaa
0
*/
kruskal:
//#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
const int MAXN = 2005;
const int INF = 0x3f3f3f3f;
int n, m, len, f[MAXN];
//string str[MAXN];//会超时!!!
char str[MAXN][MAXN];
struct Edge
{
int u, v, w;
bool operator < (const Edge& A) const
{
return w < A.w;
}
}edge[MAXN * MAXN];
int check(char a[MAXN], char b[MAXN])
{
int ans = 0;
for (int i = 0; i < len; i++)
{
if (a[i] != b[i]) ans++;
}
return ans;
}
int Find(int x) { return f[x] == x ? x : f[x] = Find(f[x]); }
void init()
{
for (int i = 0; i <= n; i++) f[i] = i;
}
int kruskal()
{
init();
sort(edge, edge + m);
int ans = 0, cnt = 0;
for (int i = 0; i < m; i++)
{
int u = edge[i].u, v = edge[i].v, w = edge[i].w;
int root1 = Find(u), root2 = Find(v);
if (root1 != root2)
{
f[root1] = root2;
ans += w;
cnt++;
if (cnt == n - 1) break;
}
}
return ans;
}
int main()
{
while (~scanf("%d", &n) && n)
{
cin.get();//读/n
for (int i = 0; i < n; i++) gets(str[i]);// cin >> str[i];
len = strlen(str[0]);// len = str[0].length();
m = 0;
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
//G[i][j] = G[j][i] = check(str[i], str[j]);
edge[m].u = i; edge[m].v = j; edge[m].w = check(str[i], str[j]);
m++;
}
}
printf("The highest possible quality is 1/%d.\n", kruskal());
}
return 0;
}
/*
4
aaaaaaa
baaaaaa
abaaaaa
aabaaaa
0
*/