卡车历史
时限:2000MS 内存限制:65536K
提交材料共计: 30032 接受: 11735
描述
先进货运有限公司使用不同类型的卡车。有些卡车用于蔬菜运送,其他用于家具或砖。该公司有自己的代码描述每种类型的卡车。该代码只是一个由七个小写字母组成的字符串(每个位置上的每个字母都有一个非常特殊的含义,但对于这个任务并不重要)。在公司发展的初期,只使用了一种卡车类型,后来又衍生出其他类型的卡车,然后从新的类型中衍生出另一种类型,等等。
今天,ACM已经足够富有,足以让历史学家们去研究它的历史了。有一件事是历史学家试图找出的,那就是所谓的派生计划-即如何派生出卡车类型。他们把卡车类型的距离定义为卡车类型代码中不同字母的位置数。他们还认为,每种卡车类型都是从另外一辆卡车中派生出来的(第一种卡车类型除外,它不是从任何其他类型衍生出来的)。然后将派生计划的质量定义为
其中,求和在派生计划中对所有类型的类型进行处理,使tO是原始类型和td派生自它和d(T0,td)的类型是类型的距离。
因为历史学家失败了,你要写一个计划来帮助他们。给定卡车类型的代码,您的程序应该找到派生计划的最高质量。
输入
输入由几个测试用例组成。每个测试用例以一个包含卡车类型数量的直线开始,n,2<=n<=2 000。下面的每个输入行都包含一个卡车类型代码(一个由七个小写字母组成的字符串)。您可以假设代码唯一地描述了卡车,也就是说,这些N中没有两个是相同的。输入在卡车类型的数目处以零结束。
输出
对于每个测试用例,您的程序应该输出文本“ The highest possible quality is 1/q”,其中1/q是最佳派生计划的质量。
样本输入
4
aaaaaaa
baaaaaa
abaaaaa
时限:2000MS 内存限制:65536K
提交材料共计: 30032 接受: 11735
描述
先进货运有限公司使用不同类型的卡车。有些卡车用于蔬菜运送,其他用于家具或砖。该公司有自己的代码描述每种类型的卡车。该代码只是一个由七个小写字母组成的字符串(每个位置上的每个字母都有一个非常特殊的含义,但对于这个任务并不重要)。在公司发展的初期,只使用了一种卡车类型,后来又衍生出其他类型的卡车,然后从新的类型中衍生出另一种类型,等等。
今天,ACM已经足够富有,足以让历史学家们去研究它的历史了。有一件事是历史学家试图找出的,那就是所谓的派生计划-即如何派生出卡车类型。他们把卡车类型的距离定义为卡车类型代码中不同字母的位置数。他们还认为,每种卡车类型都是从另外一辆卡车中派生出来的(第一种卡车类型除外,它不是从任何其他类型衍生出来的)。然后将派生计划的质量定义为
1/Σ(to,td)d(to,td)
其中,求和在派生计划中对所有类型的类型进行处理,使tO是原始类型和td派生自它和d(T0,td)的类型是类型的距离。
因为历史学家失败了,你要写一个计划来帮助他们。给定卡车类型的代码,您的程序应该找到派生计划的最高质量。
输入
输入由几个测试用例组成。每个测试用例以一个包含卡车类型数量的直线开始,n,2<=n<=2 000。下面的每个输入行都包含一个卡车类型代码(一个由七个小写字母组成的字符串)。您可以假设代码唯一地描述了卡车,也就是说,这些N中没有两个是相同的。输入在卡车类型的数目处以零结束。
输出
对于每个测试用例,您的程序应该输出文本“ The highest possible quality is 1/q”,其中1/q是最佳派生计划的质量。
样本输入
4
aaaaaaa
baaaaaa
abaaaaa
aabaaaa
0
样本输出The highest possible quality is 1/3.
题意大概是这样的:用一个7位的string代表一个编号,两个编号之间的distance代表这两个编号之间不同字母的个数。一个编号只能由另一个编号“衍生”出来,代价是这两个编号之间相应的distance,现在要找出一个“衍生”方案,使得总代价最小,也就是distance之和最小。
例如有如下4个编号:
aaaaaaa
baaaaaa
abaaaaa
aabaaaa
显然的,第二,第三和第四编号分别从第一编号衍生出来的代价最小,因为第二,第三和第四编号分别与第一编号只有一个字母是不同的,相应的distance都是1,加起来是3。也就是最小代价为3。
问题可以转化为最小代价生成树的问题。因为每两个结点之间都有路径,所以是完全图。
此题的关键是将问题转化为最小生成树的问题。每一个编号为图的一个顶点,顶点与顶点间的编号差即为这条边的权值,题目所要的就是我们求出最小生成树来。这里我用prim算法来求最小生成树。
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define NUM 2002
using namespace std;
int Graph[NUM][NUM];
int N;//顶点数;
char str[NUM][8];
struct node //保存key值的结点
{
int v;
int key;
friend bool operator<(node a, node b) //自定义优先级,key小的优先
{
return a.key > b.key;
}
};
int parent[NUM]; //每个结点的父节点
bool visited[NUM]; //是否已经加入树种
node vx[NUM]; //保存每个结点与其父节点连接边的权值
priority_queue<node> q; //优先队列stl实现、、将排序的功能用其来实现;
//将自动的按照相应的排序方式排序
void Prim()
{
for(int i = 1; i <= N; i++) //初始化
{
vx[i].v = i;
vx[i].key = 1<<30;
parent[i] = -1;
visited[i] = false;
}
vx[1].key = 0;
q.push(vx[1]);
while(!q.empty())
{
node nd = q.top(); //取队首,记得赶紧pop掉
q.pop();
if(visited[nd.v] == true) //深意,因为push机器的可能是重复但是权值不同的点,我们只取最小的
continue;
int st = nd.v;
visited[nd.v] = true;
for(int j = 1; j <= N; j++)
{
if(j!=st && !visited[j] && Graph[st][j] < vx[j].key) //判断
{
parent[j] = st;
vx[j].key = Graph[st][j];
q.push(vx[j]);
}
}
}
}
int main()
{
while(scanf("%d",&N)&&N!=0){
for(int i = 1;i<=N;i++)
scanf("%s",str[i]);
memset(Graph, 124,sizeof(Graph));
for(int i= 1;i<=N;i++)
for(int j = i+1;j<=N;j++){
int w = 0;
for(int k = 0;k<7;k++)
if(str[i][k]!=str[j][k])
w++;
Graph[j][i] = Graph[i][j] = w;
}
Prim();
int ans = 0;
for(int i = 1;i<=N;i++)
ans+=vx[i].key;
printf("The highest possible quality is 1/%d.\n",ans);
}
return 0;
}