L3-005 垃圾箱分布 (30 分)

大家倒垃圾的时候,都希望垃圾箱距离自己比较近,但是谁都不愿意守着垃圾箱住。所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。

现给定一个居民区的地图,以及若干垃圾箱的候选地点,请你推荐最合适的地点。如果解不唯一,则输出到所有居民点的平均距离最短的那个解。如果这样的解还是不唯一,则输出编号最小的地点。

输入格式:

输入第一行给出4个正整数:N(≤103)是居民点的个数;M(≤10)是垃圾箱候选地点的个数;K(≤104)是居民点和垃圾箱候选地点之间的道路的条数;DS​是居民点与垃圾箱之间不能超过的最大距离。所有的居民点从1到N编号,所有的垃圾箱候选地点从G1到GM编号。

随后K行,每行按下列格式描述一条道路:

P1 P2 Dist

其中P1P2是道路两端点的编号,端点可以是居民点,也可以是垃圾箱候选点。Dist是道路的长度,是一个正整数。

输出格式:

首先在第一行输出最佳候选地点的编号。然后在第二行输出该地点到所有居民点的最小距离和平均距离。数字间以空格分隔,保留小数点后1位。如果解不存在,则输出No Solution

输入样例1:

4 3 11 5
1 2 2
1 4 2
1 G1 4
1 G2 3
2 3 2
2 G2 1
3 4 2
3 G3 2
4 G1 3
G2 G1 1
G3 G2 2

输出样例1:

G1
2.0 3.3

输入样例2:

2 1 2 10
1 G1 9
2 G1 20

输出样例2:

No Solution

题意理解:该题要注意垃圾候选点即使该垃圾点没有落位,也可以走那条路。然后关于图的操作还不够熟练,以及对于四舍五入问题需要注意。不同编译器可能不同

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1015;
const int E=20010;
int n,m,k,D_s;
int h[N],e[E],en[E],dis[E];
int cnt=0;
struct res_node{
    int index;
    double min_dis;
    double average_dis;
};
res_node res[15];
int num=0;
void add(int i,int j,int m)
{   dis[cnt]=m;
    e[cnt]=j;
   en[cnt]=h[i];
   h[i]=cnt++;
}//关于增边的操作
bool cmp(res_node a,res_node b)
{  if(a.min_dis==b.min_dis)
    {if(a.average_dis==b.average_dis)
          return a.index<b.index;
      else
      {return a.average_dis<b.average_dis;}}
      else return a.min_dis>b.min_dis;
}//最后判断顺序,结果的输出
int str_int(string a)
{
    if(a[0]=='G')
    {
        return 1000+str_int(a.substr(1,a.size()-1));
    }
    else
    {
        int sum=0;
        for(int i=0;i<a.size();i++)
        {   sum*=10;
            sum+=a[i]-'0';
        }
        return sum;
    }
}//关于题目转换
void dfs(int i)
{
    int vis[N];
    memset(vis,0x3f,sizeof vis);
    vis[i]=0;
    queue<int>node;
    node.push(i);
    while(!node.empty())
    {
        int t=node.front();
        node.pop();
        for(int j=h[t];j!=-1;j=en[j]) {
            int m = e[j];
            if (vis[m] > vis[t] + dis[j])
            {
                vis[m] = vis[t] + dis[j];
                node.push(m);
            }
        }//节点更新注意符号
    }
   int sum_dis=0;
    double min_dis=0x3f;
    int flag=1;
    for(int i=1;i<=n;i++)
    {
        if (vis[i] > D_s) {
            flag = 0;
            break;
        }
        if(vis[i]<min_dis)
            min_dis=vis[i];
        sum_dis+=vis[i];
    }
    if(flag)
    {
        res[num].index=i;
        res[num].min_dis=min_dis;
        res[num].average_dis=double(sum_dis)/n;
        num++;

    }

return;
}//dfs

int main()
{
cin>>n>>m>>k>>D_s;
memset(h,-1,sizeof h);
for(int i=0;i<k;i++)
{
    string a,b;
    int c;
    cin>>a>>b>>c;
    int from=str_int(a);
    int to=str_int(b);
    add(from,to,c);
    add(to,from,c);
}
for(int i=0;i<m;i++)
{
dfs(i+1+1000);
}

if(num!=0) {
    sort(res, res + num, cmp);
    cout << "G" << res[0].index - 1000 << endl;
    printf("%.1f %.1f", res[0].min_dis, res[0].average_dis);
}
else cout<<"No Solution";
return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值