PAT_A_1072

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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值