这道题是求最小生成树。很久之前是用kruskal算法求的(之前已经用过这个模板很多次),但是超时了,这里是稠密图,对所有边排序是非常耗时的操作。这里改用没有优化的prim算法(用的是数组而不是heap,这意味着每次选最近的节点都需要过一遍数组,O(N))。但是还是很轻松地通过了。
thestoryofsnow | 1789 | Accepted | 160K | 438MS | C++ | 1591B |
/*
ID: thestor1
LANG: C++
TASK: poj1789
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>
using namespace std;
const int MAXN = 2000;
bool inset[MAXN];
int dis[MAXN];
// each line is a 7-character string
// therefore, the maximum difference is 7
const int MAXDIFF = 7;
char lines[MAXN][MAXDIFF + 1];
int diff(int u, int v)
{
int d = 0;
for (int i = 0; lines[u][i] != '\0' && lines[v][i] != '\0'; ++i)
{
if (lines[u][i] != lines[v][i])
{
d++;
}
}
return d;
}
int minu(const int N)
{
int mindis = MAXDIFF, u = 0;
for (int i = 0; i < N; ++i)
{
if (!inset[i] && dis[i] < mindis)
{
mindis = dis[i];
u = i;
}
}
return u;
}
int prim(const int N)
{
for (int i = 0; i < N; ++i)
{
inset[i] = false;
}
for (int i = 0; i < N; ++i)
{
dis[i] = MAXDIFF;
}
int source = 0;
dis[source] = 0;
int mst = 0;
for (int i = 0; i < N; ++i)
{
int u = minu(N);
inset[u] = true;
mst += dis[u];
for (int i = 0; i < N; ++i)
{
if (!inset[i])
{
int d = diff(u, i);
if (d < dis[i])
{
dis[i] = d;
}
}
}
}
return mst;
}
int main()
{
int N;
while (scanf("%d", &N) && N)
{
for (int i = 0; i < N; ++i)
{
scanf("%s", lines[i]);
}
// for (int i = 0; i < N; ++i)
// {
// printf("%s\n", lines[i]);
// }
printf("The highest possible quality is 1/%d.\n", prim(N));
}
return 0;
}