题意:给定几处居民住所与几处预选加油站点,求离最近的居民住所最远且所有居民都在该站点服务区内的加油站点,如果有多个,则选择平均距离最小的,再有多个,选择序号最小的。
思路:刚开始不知道未选中的加油站是否应该算入路径中,后面看了一下样例才知道未被选中的加油站的路也是可以使用的,所以我们可以将加油站也看作结点排在居所后面,然后再对每个加油站跑一遍最短路,同时找出最短路,最长路(计算是否在服务区内),总路径(算平均距离)。
坑点:样例是经过四舍五入计算出来的,但是实际不需要进行四舍五入,不然最后一个测试点过不了。
#include<bits/stdc++.h>
using namespace std;
int dist[1100];
bool vis[1100];
int e[1100][1100];
int n,m,k,range;
void dijks(int root,long long &sum,long long &mm,long long &mx){
memset(dist,0x3f,sizeof dist);
memset(vis,0,sizeof vis);
dist[root]=0;
for(int i=1;;i++){
int u=-1,mi=0x3f3f3f3f;
for(int j=1;j<=n+m;j++){
if(!vis[j]&&mi>dist[j]){
u=j;mi=dist[j];
}
}
if(u==-1)break;
vis[u]=1;
if(u<=n){//如果该结点是居所,则更新
sum=sum+dist[u];
mm=min(mm,(long long)dist[u]);
mx=max(mx,(long long)dist[u]);
// cout<<sum<<' '<<mi<<' '<<mx<<endl;;
}
for(int j=1;j<=n+m;j++){
if(!vis[j]){
dist[j]=min(dist[j],dist[u]+e[u][j]);
}
}
}
}
int main(){
cin>>n>>m>>k>>range;
memset(e,0x3f,sizeof e);
for(int i=1;i<=k;i++){
string a,b;
int x,y,d;
cin>>a>>b>>d;
if(a[0]=='G'){
x=stoi(a.substr(1,a.size()-1))+n;
}else x=stoi(a);
if(b[0]=='G'){
y=stoi(b.substr(1,b.size()-1))+n;
}else y=stoi(b);
// cout<<x<<' '<<y<<endl;
e[x][y]=e[y][x]=d;
}
long long pos=0,mini,ave;
for(int i=n+1;i<=n+m;i++){
long long sum=0,mi=INT_MAX,mx=0;
dijks(i,sum,mi,mx);
// cout<<sum<<' '<<mi<<' '<<mx<<endl;;
if(mx>range)continue;
if(!pos){
pos=i;
mini=mi;
ave=sum;
continue;
}
if(mini<mi){
pos=i;
mini=mi;
ave=sum;
}else if(mini==mi&&ave>sum){
pos=i;
mini=mi;
ave=sum;
}
}
if(pos){
cout<<"G"<<pos-n<<endl;
printf("%.1lf %.1lf",(double)mini,(double)ave/n);
}else cout<<"No Solution";
}
(debug弄了一个多小时,找坑点又半小时,做一题,一天又快没了)