http://codeforces.com/gym/100703/problem/A
题意是n行字符串,长度m
先按题目求出每行之间的“距离”
然后要求 把所有字符串连起来, 输出生成数 中 两个字符串距离的最大值
法1
此题可以 先对for两遍 o(n^2) n=1000求出所有边
然后按边权升序排序, 然后 每天添加一条边就用并查集把两个点合并,
如果取出的边 的两点根节点想同,就丢掉,否则选取 最后得到的也是最优的
//
法2
当时我是用优先队列做的 ,先得到一条距离最小的边
vis标记掉两个点
然后把 所有与这两个顶点 连的所有边 都丢到优先队列里
然后取出最顶端的,即最小的边,如果不满足 ( 一端点被选过,另一端点没被选过) 就丢掉,如果满足就选取该边
并把该没选过的点用vis标记为选过,
然后把 所有与这一个顶点 连的所有边 都丢到优先队列里
不断重复 也是最优的 不过麻烦了点
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#define MAX 1000005
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
struct node
{
int dist;
int x;
bool operator < (const node& b) const
{
return dist>b.dist;
}
};
int ans[1005][1005];
char tm[1005][35];
int n,m;
int ok=0;
int min_point_x=0;
int min_point_y=0;
int mark=900;
int cal(int x1,int x2)
{
int i;
int maxx=0;
for (i=1;i<=m;i++)
{
if (abs(tm[x1][i]-tm[x2][i])>maxx)
maxx=abs(tm[x1][i]-tm[x2][i]);
}
ans[x1][x2]=maxx;
if (maxx<mark)
{
mark=maxx;
min_point_x=x1;
min_point_y=x2;
}
// cout<<x1<<"---"<<x2<<"---dist:"<<maxx<<endl;
return 0;
}
int cmp(node a,node b)
{
return a.dist<b.dist;
}
int vis[1005];
priority_queue <node> qq;
int main()
{
int i,j;
scanf("%d%d",&n,&m);
getchar();
for (i=1;i<=n;i++)
{
scanf("%s",tm[i]+1);
}
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
{
if (j==i) continue;
cal(i,j);
}
}
int maxxxx=0;
node tmp;
tmp.x= min_point_x;
vis[tmp.x] =1;
node ttt;
for (i=1;i<=n;i++)
{
if (ans[tmp.x][i]==0||vis[i]==1) continue;
ttt.x=i;
ttt.dist=ans[tmp.x][i];
qq.push(ttt);
}
tmp.x= min_point_y;
vis[tmp.x] =1;
for (i=1;i<=n;i++)
{
if (ans[tmp.x][i]==0||vis[i]==1) continue;
ttt.x=i;
ttt.dist=ans[tmp.x][i];
qq.push(ttt);
}
node tm;
while(!qq.empty())
{
tm=qq.top();
qq.pop();
if (vis[tm.x]==1) continue;
vis[tm.x]=1;
if (tm.dist>mark)
mark=tm.dist;
for (i=1;i<=n;i++)
{
if (ans[tm.x][i]==0||vis[i]==1) continue;
ttt.x=i;
ttt.dist=ans[tm.x][i];
qq.push(ttt);
}
}
printf("%d\n",mark);
return 0;
}