http://www.patest.cn/contests/pat-a-practise/1072
题目大意:
要建一个加油站 给定地图 其中一共有 M(M <=10)个候选点 N(N<=1000)个住宅 要求选出最佳的候选点 符合以下要求
1、所以住宅都应在加油站的服务范围 Ds 中
2、符合1要求下 保证离所有住宅都尽量远(安全考虑 我们判断时 只需判断离最近的住宅尽量远就行)
3、符合1、2 若有多个候选点 则选出距离之和最小的(题目描述是平均距离最小 相同意思)
4、经过1、2、3筛选还得不到最佳的 则选择候选点中下标最小的
//测试样例全过
#include<stdio.h>
#include<string.h>
#define Inf 1<<30
int n,m,k,d;
int map[1100][1100],vst[1100],dis[1100];
typedef struct
{
int total;
int imin;
int mark;
} Node;
Node node[20];
void Dijstra(int index)
{
int i,j,k,imax;
dis[index]=0;
//初始化 源点 index
for(i=1; i<n+m; i++)
{
imax=Inf;
for(j=1; j<=1000+m; j++)
{
if(!vst[j]&&dis[j]<imax)
{
imax=dis[j];
k=j;
}
if(j==n) j=1000;
}
//第一次 k 的值肯定是index 即第一个加到S集中的是源点 因为除dis[index]=0<imax 其余dis[i] 都初始为INF
vst[k]=1;
for(j=1; j<=1000+m; j++)
{
if(!vst[j])
{
if(dis[k]+map[k][j]<dis[j])
{
dis[j]=dis[k]+map[k][j];
}
}
if(j==n) j=1000;
}
}
}
int main()
{
int i,j,dist;
char from[10],to[10];
int fsum,tsum,tmp;
while(scanf("%d %d %d %d",&n,&m,&k,&d) != EOF)
{
for(i=1; i<=1010; i++)
{
for(j=1; j<=1010; j++)
{
map[i][j]=Inf;
}
}
for(i=0; i<k; i++)
{
scanf("%s %s %d",from,to,&dist);
//处理地图
int lenf=strlen(from);
tmp=1;
if(from[0]=='G')
{
fsum=1000+from[lenf-1]-'0';
for(j=lenf-2; j>=1; j--)
{
tmp=tmp*10;
fsum=fsum+(from[j]-'0')*tmp;
}
}
else
{
fsum=from[lenf-1]-'0';
for(j=lenf-2; j>=0; j--)
{
tmp=tmp*10;
fsum=fsum+(from[j]-'0')*tmp;
}
}
int lent=strlen(to);
tmp=1;
if(to[0]=='G')
{
tsum=1000+to[lent-1]-'0';
for(j=lent-2; j>=1; j--)
{
tmp=tmp*10;
tsum=tsum+(to[j]-'0')*tmp;
}
}
else
{
tsum=to[lent-1]-'0';
for(j=lent-2; j>=0; j--)
{
tmp=tmp*10;
tsum=tsum+(to[j]-'0')*tmp;
}
}
//printf("%d %d\n",fsum,tsum);
map[fsum][tsum]=map[tsum][fsum]=dist;
//无向图
}
int rtotal,rmin,flag;
for(i=1001; i<=1000+m; i++)
//1001-1010 代表 G1-G10 这些点分别调用Dijstra(i) 求出各自到所有住宅的最短路径
{
for(j=1; j<=1010; j++)
{//初始化 集合 S 最短路径
vst[j]=0;
dis[j]=Inf;
}
Dijstra(i);
//for(j=1;j<=n;j++)
//printf("%d ",dis[j]);
//printf("\n");
flag=0;
rtotal=0;
for(j=1; j<=n; j++)
{//考察第Gi个候选点中 Gi 到每个住宅的最短距离是否在服务范围内
if(dis[j]<=d)
{//如果在范围内 则累加 (用于后面的判优选取 选取距离和最小的候选点)
rtotal=rtotal+dis[j];
}
else
{
//如果有某一个点不住范围内 则该候选点不符合要求 标志flag = 1
flag=1;
}
}
if(flag)
{
//GI不符合候选要求 其mark 值置为 0
node[i-1000].mark=0;
}
else
{
//若Gi到所有住宅的最短距离都在服务范围内
//则填写该点的属性 mark = 1 路径和 total = total
node[i-1000].mark=1;
node[i-1000].total=rtotal;
rmin=Inf;
for(j=1; j<=n; j++)
{
//选出该Gi到所有住宅最短距离最小的值
//用于后面的判优选取 因为Gi离所有住宅要尽量远 判断离最近住宅谁最远就行
if(dis[j]<rmin)
rmin=dis[j];
}
node[i-1000].imin=rmin;
}
}
int rindex=-1,maxmin=-1,maxtotal=Inf;
//最终选择 选出最优候选点
for(i=1; i<=m; i++)
{
if(node[i].mark)
{//如果该点符合服务范围要求
if(node[i].imin>maxmin)
{//离最近住宅距离
maxmin=node[i].imin;
//距离综合
maxtotal=node[i].total;
//标记该点
rindex=i;
}
else if(node[i].imin==maxmin)
{//如果离最近住宅距离一样
if(node[i].total<maxtotal)
{
//选取距离和最小的
maxtotal=node[i].total;
rindex=i;
}
}
//应该还有一个判断 就是距离和也一样 选取Gi 中 i 最小的 估计测试数据没出这种极端的数据
}
}
if(rindex==-1)
//如果连服务范围要求都找不到符合的 那肯定是没有解了
//如果仅有一个候选点符合服务范围要求 那就它了
{
printf("No Solution\n");
}
else
{
printf("G%d\n",rindex);
printf("%.1f %.1f\n",node[rindex].imin*1.0,node[rindex].total*1.0/n);
}
}
return 0;
}