首页 > 试题广场 >

Gas Station (30)

[编程题]Gas Station (30)
  • 热度指数:5220 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
A gas station has to be built at such a location that the minimum distance between the station and any of the residential housing is as far away as possible. However it must guarantee that all the houses are in its service range.
Now given the map of the city and several candidate locations for the gas station, you are supposed to give the best recommendation. If there are more than one solution, output the one with the smallest average distance to all the houses. If such a solution is still not unique, output the one with the smallest index number.

输入描述:
Each input file contains one test case.  For each case, the first line contains 4 positive integers: N (<= 103), the total number of houses; M (<= 10), the total number of the candidate locations for the gas stations; K (<= 104), the number of roads connecting the houses and the gas stations; and DS, the maximum service range of the gas station.  It is hence assumed that all the houses are numbered from 1 to N, and all the candidate locations are numbered from G1 to GM.
Then K lines follow, each describes a road in the format
P1 P2 Dist
where P1 and P2 are the two ends of a road which can be either house numbers or gas station numbers, and Dist is the integer length of the road.


输出描述:
For each test case, print in the first line the index number of the best location.  In the next line, print the minimum and the average distances between the solution and all the houses.  The numbers in a line must be separated by a space and be accurate up to 1 decimal place.  If the solution does not exist, simply output “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

输出

G1
2.0 3.3
啥头像
几个需要注意的地方:
        1.输入判断。  可能会有“G5 G5 10”这样的输入,注意筛选,选取最小值
        2.判断是住宅还是加油站。
        3.判断是否超出加油站覆盖范围
        4.多解时最优解的筛选

总体思路:
        1.输入数据
        2.用Floyd算法求出两点之间的最短距离
        3.逐个判断哪个加油站是有效最优解
        4.按要求输出结果

代码如下:
#include <iostream>
#include <vector>
#include <iomanip>
#include <limits.h>
#include <stdio.h>

using namespace std;

int main()
{
    // 读入数据
    int N, M, K, ds;
    scanf("%d %d %d %d", &N, &M, &K, &ds);
    vector<vector<int> > dist(N+M+1, vector<int>(N+M+1, INT_MAX/2));
    // 给对角线填上值
    for(int i=1; i<=N+M; i++) {
        dist[i][i] = 0;
    }
    int src, des, tempDist; char str[5];
    for(int i=0; i<K; i++) {
        scanf("%s", str);
        if(str[0] == 'G') {
            sscanf(str+1,"%d", &src);
            src += N;
        } else {
            sscanf(str,"%d", &src);
        }
        scanf("%s", str);
        if(str[0] == 'G') {
            sscanf(str+1,"%d", &des);
            des += N;
        } else {
            sscanf(str,"%d", &des);
        }
        scanf("%d", &tempDist);
        dist[src][des] = min(tempDist, dist[src][des]);
        dist[des][src] = dist[src][des];
    }

    // floyd优化
    int i, j;
    for(int k=1; k<=N+M; k++) {
        for(i=1; i<=N+M; i++) {
            for(j=1; j<=N+M; j++) {
                if(dist[i][j] > (dist[i][k]+dist[k][j])) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }

    // 选出最优解
    bool isFind = false, isOk;
    int minDist=0, tempMinDist, index;
    int sumDist=INT_MAX/2, tempSumDist;
    for(i=N+1; i<=N+M; i++) {
        tempSumDist = 0; isOk = true;
        tempMinDist = INT_MAX;
        for(j=1; j<=N; j++) {
            if(dist[i][j] > ds) {
                isOk = false; break;
            } else {
                tempSumDist += dist[i][j];
                if(dist[i][j] < tempMinDist) {
                    tempMinDist = dist[i][j];
                }
            }
        }
        if(isOk) {
            if(tempMinDist > minDist) {
                isFind = true; index = i;
                minDist = tempMinDist;
                sumDist = tempSumDist;
            } else if (tempMinDist == minDist && tempSumDist < sumDist) {
                isFind = true; index = i;
                sumDist = tempSumDist;
            }
        }
    }

    // 输出结果
    if(isFind) {
        double avg = sumDist*1.0/N;
        printf("G%d\n%d.0 %.1f\n", index-N, minDist, avg);
    } else {
        printf("No Solution\n");
    }
    return 0;
} 


发表于 2015-12-04 18:44:16 回复(0)
蛋疼,不知道错哪,测试数据看不完整

#define INF 0x3fffffff
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN=1e3+15;
const int MAXSTR=10;

int N,M,K,Ds,minsumd=INF,maxd=-1,mind[12],sel=-1;
int vex[MAXN][MAXN],d[MAXN];
bool visited[MAXN];
int read(){
    int v;
    char s[MAXSTR];
    scanf("%s",s);
    if(s[0]=='G'){
        sscanf(s+1,"%d",&v);
        v+=N;
    }else
        sscanf(s,"%d",&v);
    return v;
}
int select(){
    int p=-1,mind=INF;
    for(int i=1;i<=N+M;++i)
        if(!visited[i] && mind>d[i]) mind=d[p=i];
    return p;
}
void Dijkstra(int G){
    fill(visited,visited+MAXN,false);
    fill(d,d+MAXN,INF);
    d[G+N]=0;
    for(int i=1;i<=N+M;++i){
        int u=select();
        if(u==-1) break;
        visited[u]=true;
        for(int v=1;v<=N+M;++v)
            if(!visited[v] && vex[u][v]!=INF && d[v]>d[u]+vex[u][v])
                d[v]=d[u]+vex[u][v];
    }
    int v,sumd=0;
    bool badGS=false;
    for(v=1;v<=N && !badGS;++v)
        if(d[v]<=Ds){
            sumd+=d[v];
            if(mind[G]>d[v]) mind[G]=d[v];
        }else badGS=true;
    if(!badGS && maxd<mind[G]){
        maxd=mind[G];
        minsumd=sumd;
        sel=G;
    }else if(!badGS && maxd==mind[G] && minsumd>sumd){
        minsumd=sumd;
        sel=G;
    }
}
int main()
{
    int a,b,L;
    fill(vex[0],vex[0]+MAXN*MAXN,INF);
    fill(mind,mind+12,INF);
    scanf("%d%d%d%d\n",&N,&M,&K,&Ds);
    for(int i=1;i<=K;++i){
        a=read();
        b=read();
        scanf("%d",&L);
        vex[a][b]=vex[b][a]=L;
    }
    for(int g=1;g<=M;++g)
        Dijkstra(g);
    if(sel==-1)
        printf("No Solution\n");
    else
        printf("G%d\n%.1f %.1f\n",sel,mind[sel]+0.0,(minsumd+0.0)/N);
    return 0;
}

发表于 2018-08-18 00:53:47 回复(4)
本题细节太多,做完心很累
#pragma warning (disable:4996)
#include <iostream>
#include <cstdlib>
#include <limits.h>
#include <vector>
#include <algorithm>
using namespace std;

#define MAX 1009
int N, M, K; double Ds;
int d[MAX][MAX];

int res_id;
double max_min_d = 0, min_aver_d = INT_MAX;

int p_id(char* x) {
    if (x[0] == 'G')return atoi(x + 1) + N;
    else return atoi(x);
}

int main()
{
    cin >> N >> M >> K >> Ds;
    for (int i = 1; i <= N + M; ++i)
        for (int j = 0; j <= N + M; ++j)
            d[i][j] = INT_MAX / 2;
        
    for (int i = 1; i <= N + M; ++i) d[i][i] = 0;
    
    for (int i = 0; i < K; ++i) {
        char p1[100], p2[100]; int tmp;
        cin >> p1 >> p2 >> tmp;
        int n1 = p_id(p1), n2 = p_id(p2);
        d[n1][n2] = min(d[n1][n2], tmp);//专门处理起点-终点间有多条边的情况(包括自环)
        d[n2][n1] = d[n1][n2];
    }

    //Floyd
    for (int k = 1; k <= N + M; ++k)
        for (int i = 1; i <= N + M; ++i)
            for (int j = 1; j <= N + M; ++j)
                if (d[i][j] > d[i][k] + d[k][j])
                    d[i][j] = d[i][k] + d[k][j];


    bool isFind = false;
    for (int gi = N + 1; gi <= N + M; ++gi) {
        bool G_OK = true;
        int tmp_sum = 0.0;
        int min_d = INT_MAX;
        for (int i = 1; i <= N; ++i) {
            if (d[gi][i] > Ds) {
                G_OK = false; break;
            }
            tmp_sum += d[gi][i];
            if (min_d > d[gi][i])//注意!要保证min_d一开始一定要大于d,两者初始化分别为INT_MAX和INT_MAX/2
                min_d = d[gi][i];
        }
        if (!G_OK)continue;

        if (max_min_d <= min_d) {
            if (max_min_d < min_d) {
                max_min_d = min_d;
                isFind = true; res_id = gi - N;
                min_aver_d = tmp_sum * 1.0 / N;
            }
            else if (min_aver_d > tmp_sum * 1.0 / N) {
                isFind = true; res_id = gi - N;
                min_aver_d = tmp_sum * 1.0 / N;
            }
        }
    }

    if (isFind) {
        cout << 'G' << res_id << endl;
        printf("%.1f %.1f", max_min_d, min_aver_d);
    }
    else cout << "No Solution";
    return 0;
}


发表于 2021-03-04 07:14:44 回复(0)
思路:
1. 使用堆优化的dijikstra算法求出每一个gas station 到house的最短距离
2. gas station的index =  N + G后面的数字

自认为代码写得比较优美。

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#include <cmath>

using namespace std;
int N, M, K;
float Ds;

vector<pair<int, float>> edges[10005];
int main() {
    scanf("%d %d %d %f", &N, &M, &K, &Ds);
    for(int i = 0 ; i < K; i ++)
    {
        char u[6], v[6];
        float w;
        scanf("%s", &u);
        scanf("%s",&v);
        scanf("%f",&w);
        int uIdx, vIdx;
        uIdx = (u[0] == 'G') ? N + atoi(u+1) : atoi(u);
        vIdx = (v[0] == 'G') ? N + atoi(v+1) : atoi(v);

        edges[uIdx].push_back({vIdx, w});
        edges[vIdx].push_back({uIdx, w});
    }

    float resultMinDist = -1, resultAvgDist = 0.0;
    int resultIdx = N+1;

    for(int i = N + 1; i <= N + M; i ++)
    {
        priority_queue<pair<float, int>> que; // minDist, idx
        vector<float> minDist(N+M+1, -1);
        //vector<bool> visited(N+M+1, false);
        int rootIdx = i;
        minDist[rootIdx] = 0;
        que.push({minDist[rootIdx], rootIdx});
        while( !que.empty())
        {
            auto a = que.top();
            int idx = a.second;
            que.pop();
            for(pair<int, float> e : edges[idx])
            {
                int adjIdx = e.first;
                float w = e.second;
                if (minDist[adjIdx] < 0 || minDist[adjIdx] > w + minDist[idx])
                {
                    minDist[adjIdx] = w + minDist[idx];
                    que.push({minDist[adjIdx], adjIdx});
                }
            }
        }
        // summary
        float minServeDist = -1, avgServeDist = 0.0;
        bool failFlag = false;
        for(int j = 1; j <= N; j++)
        {
            if(minDist[j] > Ds)
            {
                failFlag = true;
                break; // fail
            }
            else
            {
                if(minServeDist < 0)
                    minServeDist = minDist[j];
                else
                    minServeDist = min(minServeDist, minDist[j]);

                avgServeDist += minDist[j];
            }
        }
        if(!failFlag)
        {
            avgServeDist /= N;
            if (resultMinDist < 0 || resultMinDist < minServeDist ||
                (resultMinDist == minServeDist && avgServeDist < resultAvgDist))
            {
                resultMinDist = minServeDist;
                resultAvgDist = avgServeDist;
                resultIdx = i;
            }
        }

    }
    if(resultMinDist > 0) {
        printf("G%d\n", resultIdx - N);
        printf("%.1f %.1f", resultMinDist, resultAvgDist);
    }
    else
        printf("No Solution");
    return 0;
}


发表于 2020-07-25 09:12:17 回复(0)
做了挺久,令人欣慰的是第一次提交就AC了。。。
题目的意思很容易看错:
需要特别注意最优解的排序依据(先按最近距离大者优先,再到平均距离小者优先,最后到编号小者优先),另外,这个最短距离以及平均距离都仅算油站到其他住宅,不是全部结点。因此存放结点时可以将住宅放前面,油站放后面,以区分对待。
#include <bits/stdc++.h>
(755)#define min(a,b) ((a)<(b)? (a):(b))
#define INF 99999999
using namespace std;
struct Road{
	int target;
	int distant;
};
int hourseNum, gasNum, roaseNum, serverDis;

//将用字符串表示的节点下标转换成整数下标
int translate(string nodeName){
	if (nodeName[0] != 'G') return atoi(nodeName.c_str());
	return hourseNum + atoi(nodeName.substr(1).c_str());
}
//答案组合
struct Result{
	int id;
	int totalDis;
	int min;
	bool operator < (const Result &b) const{
		if (min != b.min) return min > b.min;
		if (totalDis != b.totalDis) return totalDis < b.totalDis;
		return id < b.id;
	}
};
vector<Result>ansQue;
vector< vector<Road> >nodes;	//从1开始

int main(){
	//获取数据输入
	scanf("%d %d %d %d", &hourseNum, &gasNum, &roaseNum, &serverDis);
	nodes.resize(hourseNum + gasNum + 1);
	for (int i = 0; i < roaseNum; i++){
		string from, to;
		int distant;
		cin >> from >> to >> distant;
		nodes[translate(from)].push_back({ translate(to), distant });
		nodes[translate(to)].push_back({ translate(from), distant });
	}
	//对所有的油站计算最短路
	int ansIndex=-1, ansMin=INF;
	double ansAvg=0.0;
	for (int id = hourseNum + 1; id <= hourseNum + gasNum; id++) {
		vector<bool> visit(hourseNum + gasNum + 1, false);
		vector<int> distant(hourseNum + gasNum + 1, INF);	//从油站id到个个节点的距离
		//初始化数据
		distant[id] = 0;
		visit[id] = true;
		for (auto i = nodes[id].begin(); i < nodes[id].end(); i++){
			distant[i->target] = min(distant[i->target], i->distant);
		}
		//寻找以id为起点的最短路
		for (int i = 0; i < hourseNum + gasNum; i++){
			int shortest = INF, next=-1;
			//收纳最近节点
			for (int j = 1; j <= hourseNum+gasNum; j++){
				if (!visit[j] && distant[j] < shortest){
					next = j;
					shortest = distant[j];
				}
			}
			if (shortest > serverDis || next<0) break;	//虽然可以连通,但是距离超出范围
			visit[next] = true;
			//更新其他节点的最短路径
			for (auto j = nodes[next].begin(); j < nodes[next].end(); j++){
				if (distant[next] + j->distant < distant[j->target]){
					distant[j->target] = distant[next] + j->distant;
				}
			}
		}
		//分析结果并更新答案
		bool can = true;
		int totalDis = 0, minDis = INF;
		for (int i = 1; i <= hourseNum; i++){
			if (i == id) continue;
			if ( distant[i] > serverDis) {	//服务距离仅筛选住宅
				can = false;
				break;
			}
			minDis = min(minDis, distant[i]);
			totalDis += distant[i];
		}
		if (can){
			ansQue.push_back({id-hourseNum, totalDis, minDis});
		}
	}
	//输出答案
	if (ansQue.empty()){
		cout << "No Solution" << endl;
	}
	else{
		sort(ansQue.begin(), ansQue.end());
		Result ans = ansQue[0];
		printf("G%d\n%.1f %.1f\n", ans.id, double(ans.min), double(ans.totalDis) / hourseNum);
	}
	return 0;
}


发表于 2020-03-03 12:07:04 回复(0)
/*
题意:给定m个站,选择其中最优的一个,要求其到各个居民区的最短距离 最长,
若有多个解,则选择平均长度小的,仍有多个,则选择索引小的,另外要求最长距离不能超过Gi站的覆盖范围
思路:dijstra求每个Gi到居民区各点的最短路,按要求取最优结果即可,注意结果四舍五入保留一位小数。
 
这样还是蛮快的10ms,排在50多位
*/
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
#define LL long long 
using namespace std;
typedef pair<LL,int>P;
const int AX = 1e3 + 666 ;
int n , m , k ;
LL D , minu , avg ; 
struct Node {
	int to ;
	LL w ;
	Node() {}
	Node( int to , int w ):to(to),w(w) {}
};
vector<P>G[AX] ;
int vis[AX] ;
LL dis[AX] ;
void dijstra( int st ) {
	priority_queue<P,vector<P>,greater<P> >q ;
	q.push(P(0,st));
	dis[st] = 0 ;
	while( !q.empty() ) {
		int u = q.top().second;
		LL val = q.top().first ;
		q.pop();
		if( vis[u] ) continue ;
		vis[u] = 1 ;

		if( val > dis[u] ) continue ;
		for( int i = 0 ; i < (int)G[u].size() ; i++ ) {
			int to = G[u][i].second ;
			LL w = G[u][i].first ;
			if( val + w < dis[to] ) {
				dis[to] = val + w ;
				q.push(P(dis[to],to));
			}
		}
	}
}
int main() {
	int x , y , id ;
	LL w ; 
	char p1[10] , p2[10] ;
	minu = -1  ; 
	scanf("%d%d%d%lld",&n,&m,&k,&D);
	while( k-- ) {
		scanf("%s%s%lld",&p1,p2,&w);
		if( p1[0] == 'G' ) x = atoi(p1+1) + n ;
		else x = atoi(p1);
		if( p2[0] == 'G' ) y = atoi(p2+1) + n ;
		else y = atoi(p2);
		G[x].push_back(P(w,y));
		G[y].push_back(P(w,x));
	}
	for( int i = 1 ; i <= m ; i++ ) {
		memset( dis , 0x3f , sizeof(dis) );
		memset( vis , 0 , sizeof(vis) );
		dijstra(i+n);
		int f = 1 ;
		LL ans = INF , sum = 0 ;
		for( int j = 1 ; j <= n ; j++ ){
			if( dis[j] > D ){ f = 0 ; break ; }
			ans = min( ans , dis[j] );
			sum += dis[j] ; 
		}
		if( !f ) continue ; 
		if( ans > minu ){
			id = i ; 
			minu = ans ; 
			avg = sum  ;
		}else if( ans == minu ){
			if( avg > sum ){
				id = i ; 
				avg = sum ; 
			}
		}
	}
	if( minu != -1 ){
		printf("G%d\n",id);
		int tmp = ((double)avg/(double)n + 0.05)*10 ;//四舍五入保留一位小数
		printf("%.1lf %.1lf",(double)minu,(double)tmp/10.0);
	}else{
		printf("No Solution");
	}
	return 0;
}

编辑于 2020-02-24 20:47:37 回复(0)
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;

const int N = 1000, M = 20, Maxn = N + M;
const int INF = 1000000000;
struct Edge {
    int from, to, dis;
    Edge(int f, int t, int d): from(f), to(t), dis(d) {}
};
struct MD {
    int n, m;
    vector<Edge> edges;
    vector<int> G[Maxn];
    int d[Maxn], inq[Maxn];
    void Init(int nn)
    {
        n = nn;
        for(int i = 0; i < Maxn; i++)
            G[i].clear();
        edges.clear();
    }
    void AddEdge(int f, int t, int d)
    {
        edges.push_back(Edge(f, t, d));
        edges.push_back(Edge(t, f, d));
        m = edges.size();
        G[f].push_back(m - 2);
        G[t].push_back(m - 1);
    }
    void BellmanFord(int s)
    {
        memset(inq, 0, sizeof(inq));
        for(int i = 0; i < Maxn; i++)
            d[i] = INF;
        d[s] = 0;
        queue<int> q;
        inq[s] = 1;
        q.push(s);
        while(!q.empty()) {
            int u = q.front(); q.pop();
            inq[u] = 0;
            for(int i = 0; i < G[u].size(); i++) {
                Edge &e = edges[G[u][i]];
                if(d[e.to] > d[u] + e.dis) {
                    d[e.to] = d[u] + e.dis;
                    if(!inq[e.to]) {
                        inq[e.to] = 1;
                        q.push(e.to);
                    }
                }
            }
        }
    }
};
int n, m, k, ds;
float sum[M];
MD g;
int read(char *s)
{
    int x = -1;
    if(s[0] == 'G') {
        sscanf(s + 1, "%d", &x);
        x += (n - 1); //n ~ (n+m-1)
    } else {
        sscanf(s, "%d", &x);
        x--; //0 ~ (n-1)
    }
    return x;
}
int main()
{
    scanf("%d %d %d %d\n", &n, &m, &k, &ds);
    g.Init(n + m); //clear maxium
    memset(sum, 0, sizeof(sum));
    for(int i = 0; i < k; i++) {
        char s1[16], s2[16];
        int u, v, d;
        scanf("%s %s %d\n", s1, s2, &d);
        u = read(s1);
        v = read(s2);
        g.AddEdge(u, v, d);
    }
    int bestDis = -1, besti = -1;
    float bestSum = float(INF);
    for(int i = 0; i < m; i++) {
        g.BellmanFord(n + i);
        int t = INF;
        int invalid = 0;
        for(int j = 0; j < n; j++) {
            if(g.d[j] > ds || g.d[j]<bestDis) {
                invalid = 1;
                break;
            } else {
                sum[i] += g.d[j];
            };
            t = min(t, g.d[j]);
        }
        if(invalid)
            continue;
        if(t > bestDis) {
            bestDis = t;
            besti = i;
            bestSum = sum[i];
        } else if(t == bestDis && sum[i] < bestSum) {
            besti = i;
            bestSum = sum[i];
        };
    }
    if(besti == -1)
        printf("No Solution\n");
    else {
        printf("G%d\n", besti + 1);
        float dis = float(bestDis);
        float ave = sum[besti] / n; //accurate up
        printf("%.1f %.1f\n", dis, ave);
    }
    return 0;
}
看了下都是邻接表的解答,我是用边表存储的bellmanford方法
题里面写的是"accurate up to 1 decimal"
注意输出格式是%.1f
编辑于 2019-08-06 16:25:40 回复(3)
#include <iostream>
#include <cstdio>
#include <vector>
#include <climits>
#include <iomanip>

using namespace std;

int main()
{     int N,M,K,D;     cin>>N>>M>>K>>D;     vector<vector<int> > d(N+M+1, vector<int>(N+M+1,INT_MAX/2));     for(int i=0;i<=N+M;i++)         d[i][i] = 0;          int start,end,temp;     char str[5];          for(int i=0;i<K;i++)     {         cin>>str;         if(str[0]=='G')         {             sscanf(str+1, "%d", &start);             start += N;         }else             sscanf(str, "%d", &start);                      cin>>str;         if(str[0]=='G')         {             sscanf(str+1, "%d", &end);             end += N;         }else             sscanf(str, "%d", &end);                      cin>>temp;         d[start][end] = d[end][start]= min(d[start][end], temp);     }          for(int k=1;k<=N+M;k++)         for(int i=1;i<=N+M;i++)             for(int j=1;j<=N+M;j++)                 d[i][j] = min(d[i][j], d[i][k]+d[k][j]);          int isFind=false, flag;     int Min=0,tempMin,index;     int sum=INT_MAX/2,tempSum;     for(int i=N+1;i<=N+M;i++)     {         tempSum = 0;         flag = true;         tempMin = INT_MAX;         for(int j=1;j<=N;j++)         {             if(d[i][j] > D)             {                 flag = false;                 break;             }else{                 tempSum += d[i][j];                 tempMin = min(tempMin, d[i][j]);             }         }         if(flag)         {             if(tempMin > Min)             {                 isFind = true;                 index = i;                 Min = tempMin;                 sum = tempSum;             }else if(tempMin==Min && tempSum<sum){                 isFind = true;                 index = i;                 sum = tempSum;             }         }     }              if(isFind)     {         double avg = sum*1.0/N;         printf("G%d\n%d.0 %.1f\n", index-N, Min, avg);     }else         printf("No Solution\n");     return 0;
}

发表于 2018-03-07 01:13:30 回复(0)
这题一开始我根本没理解题意(难受),后来才发现是让house到station的最短距离达到最大,然后在根据平均距离排序。还有坑的地方在于牛客输入数据会有重复边,遇到重复时要选最小的边权。然后,理解 了题意后还是好写的,就是坑太多。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+20;
const int INF=0x3f3f3f3f;
int n,m,k,Ds,G[maxn][maxn],dis[maxn];//1~n:house n+1~n+m:station
bool visit[maxn];

int getId(string &s){
    if(s[0]=='G'){
        if(s.size()==2) return n+s[1]-'0';
        else return n+10;
    }else{
        return stoi(s);
    }
}
//最短路径
void dijkstra(int s,int N){
    fill(dis,dis+N+1,INF);
    fill(visit,visit+N+1,0);
    dis[s]=0;
    for(int i=1;i<=N;i++){
        int u=-1,min=INF;
        for(int j=1;j<=N;j++){
            if(!visit[j] && dis[j]<min){
                min=dis[j];
                u=j;
            }
        }
        if(u==-1) return;
        visit[u]=true;
        for(int v=1;v<=N;v++){
            if(!visit[v] && G[u][v]!=0){
                int tempDis=dis[u]+G[u][v];
                if(tempDis<dis[v]){
                    dis[v]=tempDis;
                }
            }
        }
    }
}
int main()
{   
    fill(G[0],G[0]+maxn*maxn,INF);
    cin>>n>>m>>k>>Ds;
    string p1,p2;
    int a,b,c;
    for(int i=0;i<k;i++){
        cin>>p1>>p2>>c;
        a=getId(p1);
        b=getId(p2);
        G[a][b]=G[b][a]=min(c,G[a][b]);
    }
    int choice=-1;
    double minDis=-INF,meanDis,tempMindis,tempMeandis;
    for(int i=n+1;i<=n+m;i++){
        dijkstra(i,n+m);
        if(*max_element(dis+1,dis+n+1)>Ds) continue;//存在dis>Ds
        tempMindis=*min_element(dis+1,dis+n+1);
        tempMeandis=accumulate(dis+1,dis+n+1,0)*1.0/n;
        //比较不同出发点,house到station的最短距离
        if(tempMindis>minDis){
            minDis=tempMindis;
            meanDis=tempMeandis;
            choice=i-n;
        }else if(tempMindis==minDis){
            if(tempMeandis<meanDis){
                meanDis=tempMeandis;
                choice=i-n;                
            }
        }
    }
    if(choice!=-1){
        cout<<"G"<<choice<<endl;
        printf("%.1f %.1f",minDis,meanDis);
    }else{
        cout<<"No Solution";
    }
    return 0;
}


发表于 2022-08-13 01:30:40 回复(0)
有重复边😡🤬🤬🤬🤬🤬🤬,取最小的边,浪费了一天md
#include<bits/stdc++.h>
using namespace std;

const int Max=1020;
const int INF=INT_MAX;

int n,m,k,d;
int dis[Max],G[Max][Max];
bool visit[Max];

void Dijistra(int s) {
	memset(visit,0,sizeof(visit));
	fill(dis,dis+Max,INF);
	dis[s]=0;
	for(int i=0; i<m+n; i++) {
		int u=-1,Min=INF;
		for(int j=1; j<=m+n; j++) {
			if(dis[j]<Min&&!visit[j]) {
				Min=dis[j];
				u=j;
			}
		}
		if(u==-1) return ;
		visit[u]=1;
		for(int v=1; v<=m+n; v++) {
			if(!visit[v]&&G[u][v]!=INF) {
				if(dis[v]>dis[u]+G[u][v]) {
					dis[v]=dis[u]+G[u][v];
				}
			}
		}
	}
}

int getid(char* s) {
	int i=0,l=strlen(s),id=0;
	while(i<l) {
		if(s[i]!='G')
			id=id*10+(s[i]-'0');
		i++;
	}
	if(s[0]=='G') return n+id;
	else return id;
}

int main() {
	scanf("%d %d %d %d",&n,&m,&k,&d);
	fill(G[0],G[0]+Max*Max,INF);
	for(int i=0; i<k; i++) {
		char s1[5],s2[5];
		int c;
		scanf("%s %s",s1,s2);
		int from,to;
		from=getid(s1);
		to=getid(s2);
		scanf("%d",&c);
		G[to][from]=G[from][to]=min(c,G[to][from]);
	}
	int ansid=-1;
	double ansdis=-1,ansavg=INF;
	for(int i=n+1; i<=m+n; i++) {
		double mindis=INF,minavg=0;
		Dijistra(i);
		if(*max_element(dis+1,dis+n+1)>d) continue;
		mindis=*min_element(dis+1,dis+n+1);
		minavg=accumulate(dis+1,dis+n+1,0)*1.0/n;
		if(ansdis<mindis) {
			ansid=i;
			ansdis=mindis;
			ansavg=minavg;
		} else if(ansdis==mindis&&ansavg>minavg) {
			ansid=i;
			ansavg=minavg;
		}
	}
	if(ansid==-1) printf("No Solution\n");
	else {
		printf("G%d\n",ansid-n);
		printf("%.1f %.1f\n",ansdis,ansavg);
	}
	return 0;
}

编辑于 2022-11-30 16:21:53 回复(1)
#include <bits/stdc++.h>
using namespace std;
int n,m,k,l;
#define inf 999999
int a[1200][1200];
int dis[1200][1200];
void dj(int index1){
    int i,j;
    int book[n+m+1];
    memset(book,0,sizeof(book));
    fill(dis[index1],dis[index1]+n+m+1,inf);
    dis[index1][index1]=0;
    for(i=1;i<n+m+1;i++){
        int mn=inf,u=-1;
        for(j=1;j<n+m+1;j++){
            if(book[j]==0&&mn>dis[index1][j]){
                mn=dis[index1][j];
                u=j;
            }
        }
        if(u==-1)break;
        dis[index1][u]=mn;
        book[u]=1;
        for(j=1;j<n+m+1;j++){
            if(dis[index1][u]+a[u][j]<dis[index1][j]){
                dis[index1][j]=dis[index1][u]+a[u][j];
            }
        }
    }
    return ;
}
int convert(char a[]){
    int i;
    int k=0;
    if(a[0]=='G'){
        for(i=1;a[i]!='\0';i++){
           k=k*10+a[i]-'0'; 
        }
        k+=n;        
    }
    else {
        for(i=0;a[i]!='\0';i++){
            k=k*10+a[i]-'0';
        }
    }
    return k;
}
int main(){
    scanf("%d%d%d%d",&n,&m,&k,&l);
    int i;
    int j;
    fill(a[0],a[0]+(1010)*(1010),inf);
    for(i=0;i<k;i++){
        char c[5];
        char b[5];
        scanf("%s%s",c,b);
        int s=convert(c);
        int t=convert(b);
        int dis;
        scanf("%d",&dis);
        a[s][t]=min(a[s][t],dis);
        a[t][s]=min(a[s][t],dis);
    }
    int c[n+m+1];
    fill(c,c+n+m+1,inf);
    int sum[n+m+1];
    memset(sum,0,sizeof(sum));
    int ans,ans1,ans2;
    ans=-1;
    ans1=INT_MIN;
    ans2=INT_MAX;
    for(i=n+1;i<n+m+1;i++){
        dj(i);
        for(j=1;j<=n;j++){
            sum[i]+=dis[i][j];
            if(c[i]>dis[i][j])c[i]=dis[i][j];
            if(dis[i][j]>l)break;
        }
        if(j==n+1){
            if(c[i]>ans1){
                ans=i-n;
                ans1=c[i];
                ans2=sum[i];
            }
            else if(c[i]==ans1&&sum[i]<ans2){
                ans=i-n;
                ans2=sum[i];
            }
        }
    }
    if(ans==-1){
        printf("No Solution\n");
    }
    else {
        printf("G%d\n",ans);
        printf("%.1lf %.1lf",(double)ans1,(double)ans2/n);
    }
    system("pause");
}
吐了,牛客网上案例都过了,但是PTA最后一个样例一直过不去,有大神可以给说说吗

发表于 2022-06-28 18:57:38 回复(0)
c++, 邻接矩阵
#include <iostream>
#include<map>
#include<vector>
#include<set>
#include<sstream>
#define INF 0x3fffffff
using namespace std;
struct Path
{
	int end;
	int dist;
	Path(int end, int dist) :end(end), dist(dist) {}
};

int maxDistOil = 0;
double minAverageDist = INF;
int index = -1;


void Dijstra(int start, int houses, int maxArange, int points, vector<Path>* graph) {
	bool* visited = new bool[points];
	int* pathLength = new int[points];
	int* pre = new int[points];
	for (int i = 0; i < points; i++)
	{
		visited[i] = false;
		pathLength[i] = INF;
		pre[i] = -1;
	}
	visited[start] = true;

	vector<Path> startPaths = graph[start];
	for (auto c : startPaths)
	{
		if (c.dist< pathLength[c.end])
		{
			pathLength[c.end] = c.dist;
		}
		pre[c.end] = start;
	}
	bool hasUnvisited = true;
	while (hasUnvisited)
	{
		int nextNode = -1, minLength = INF;
		hasUnvisited = false;
		for (int i = 1; i < points; i++)
		{
			if (visited[i] == false && pathLength[i] < minLength) {
				hasUnvisited = true;
				minLength = pathLength[i];
				nextNode = i;
			}
		}
		if (nextNode == -1) break;
		vector<Path> aimPath = graph[nextNode];
		visited[nextNode] = true;
		for (auto c : aimPath)
		{
			if (visited[c.end])
			{
				continue;
			}
			if (pathLength[nextNode] + c.dist < pathLength[c.end])
			{
				pathLength[c.end] = pathLength[nextNode] + c.dist;
				pre[c.end] = nextNode;
			}

		}

	}
	
	/*for (int i = 1; i < points; i++)
	{
		cout << i << " :" << pre[i] << endl;
	}
	cout << endl;
	for (int i = 1; i < points; i++)
	{
		cout << i << " :" << pathLength[i] << endl;
	}
	cout << endl;*/
	int maxDist = 0;
	int minDist = INF;
	int totalLength = 0;
	for (int i = 1; i <= houses; i++)
	{
		if (pathLength[i] > maxArange)
		{
			int index = -1;
			return;
		}
		totalLength += pathLength[i];
		if (pathLength[i] < minDist)
		{
			minDist = pathLength[i];
		}
	}
	if (maxDistOil < minDist)
	{
		maxDistOil = minDist;
		index = start;
		minAverageDist = totalLength;
	}
	else if (maxDistOil == minDist)
	{
		if (minAverageDist > totalLength) {
			// 如果平均距离更小,用这个新的index
			minAverageDist = totalLength;
			index = start;
		}
		else if (minAverageDist == totalLength) {
			if (index > start)
			{
				// 平均距离也相等,这个时候用小的id
				index = start;
			}
		}
	}


}

int main()
{
	ios::sync_with_stdio(false);
	int houses, candidates, paths, maxServiceRange;
	cin >> houses >> candidates >> paths >> maxServiceRange;
	map<string, int> candiToId;
	string name, end;
	int dist;
	int candiId = houses + 1;
	set<string> candidateNames;
	vector<Path>* graph = new vector<Path>[houses + candidates + 1];
	for (int i = 0; i < paths; i++)
	{
		cin >> name >> end >> dist;
		if (name.find("G") != -1 && candidateNames.find(name) == candidateNames.end())
		{
			candidateNames.insert(name);
			candiToId[name] = candiId;
			candiId++;
		}
		if (end.find("G") != -1 && candidateNames.find(end) == candidateNames.end())
		{
			candidateNames.insert(end);
			candiToId[end] = candiId;
			candiId++;
		}
		int startP = 0, endP = 0;
		if (candiToId.find(name) != candiToId.end())
		{

			startP = (*candiToId.find(name)).second;
		}
		else {
			startP = atoi(name.c_str());
		}
		if (candiToId.find(end) != candiToId.end()) {
			endP = (*candiToId.find(end)).second;
		}
		else {
			endP = atoi(end.c_str());
		}
		graph[startP].push_back(Path(endP, dist));
		graph[endP].push_back(Path(startP, dist));
	}

	/*
	for (auto i : candidateNames)
	{
		cout << i << " ";
	}
	for (int i = 1; i < houses+candidates+1; i++)
	{
		cout << endl;
		cout << i << ": ";
		for (auto c : graph[i]) {
			cout << c.end << " " ;
		}
	}
	cout << endl;*/
	for (auto c : candidateNames)
	{
		int startId = (*candiToId.find(c)).second;
		Dijstra(startId, houses, maxServiceRange, houses + candidates + 1, graph);
	}

	if (index == -1)
	{
		cout << "No Solution";
	}
	else {
		for (auto c : candidateNames)
		{
			int startId = (*candiToId.find(c)).second;
			if (startId == index)
			{
				cout << c << endl;
				break;
			}
		}

		printf("%d.0 %.1f", maxDistOil, minAverageDist/houses);
	}


}



发表于 2022-05-19 00:24:17 回复(0)

pat能过 这里过不了 求助!!

#include<cstring>
#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1050;
const int inf=1e9;

int n,m,k,ds,graph[N][N],d[N];
bool vis [N];

int getID(char str[]) { //这个函数对数字和g开头的字符串一视同仁
    int i=0,len=strlen(str),id=0;
    for(int i=0; i<len; i++) {
        if(str[i]!='G') {
            id=id*10+str[i]-'0';
        }
    }
    if(str[0]=='G') return n+id;
    else return id;
}
void dijkstra(int s) {
    fill(d ,d+N ,inf );
    memset( vis,0,sizeof vis);//每次进入都要初始化
    d[s]=0;

    for(int i=1; i<=m+n; i++) {

        int u=-1,min=inf;
        for(int j=1; j<=m+n; j++) {
            if(d[j]<min&&vis[j]==false) {
                min=d[j];
                u=j;
            }
        }
        if(u==-1) return ;
        vis[u]=true;//这里又写成等于等于了!!
        for(int v=1; v<=n+m; v++) {
            if(graph[u][v]!=inf&&vis[v]==false) {
                if(d[v]>d[u]+graph[u][v]) {
                    d[v]=d[u]+graph[u][v];
                }

            }
        }

    }

}
int main() {

    cin>>n>>m>>k>>ds;
    int u,v,w;
    char city1[5],city2[5];
    fill(graph[0],graph[0]+N*N,inf);
    for(int i=0; i<k; i++) {
        cin>>city1>>city2;
        u=getID(city1),v=getID(city2);
        cin>>graph[u][v];
        graph[v][u]=graph[u][v];

    }

    double ansdis=-1,ansavg=inf;
    int ansid=-1;
    for(int i=n+1; i<=n+m; i++) {
        double mindis=inf ,avg=0;
        dijkstra(i);
        for(int j=1; j<=n; j++) {
            if(d[j]>ds) {
                mindis=-1;
                break;
            }
            if(d[j]<mindis) {
                mindis=d[j];
            }
            avg+=1.0*d[j] ;
//            printf("avg=%.1f \n",avg);
        }
        if(mindis==-1) continue;
        avg/=n;
        if(mindis>ansdis) {
            ansdis=mindis;
            ansavg=avg;
            ansid=i;


        } else if(mindis==ansdis&&avg<ansavg) {
            ansid=i;
            ansavg=avg;

        }
    }
    if(ansid==-1) cout<<"No Solution"<<endl;
    else {
        cout<<"G"<<ansid-n<<endl;
        printf("%.1f %.1f",ansdis,ansavg ) ;
    }


    return 0;

}
发表于 2022-01-03 14:58:11 回复(0)
血的教训!!!

重复进行dijistra算法时一定要记得把外部数组visited和dist重新进行初始化!!!

/*
问题:得到多个点到其他顶点的最短路径矩阵,求其最小值和平均值,并按照最小值降序和平均值升序排列。输出第一个顶点的序号、最小值和平均值。
特殊要求:输入含字符串,需要进行判断和转换;输入要求保留1位小数,需要对结果进行转换。
解法:
*/
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<cstdlib>
using namespace std;
#define MAXSIZE 100000000				//距离上限,dist数组初始值

typedef struct MGnode* MGraph;		//邻接矩阵结构
struct MGnode {
	int vN, eN;
	int V[1020][1020];
};
MGraph G=new MGnode;							//全局变量
int N, M, K, D;
int visited[1020], dist[1020];
int charToInt(char* s) {
	if (s[0] == 'G') return atoi(s + 1);
	else return atoi(s) + M;
}
void Insert(int v1, int v2, int w) {
	if (w < G->V[v1][v2]) G->V[v1][v2] = G->V[v2][v1] = w;
}
void Build(int n, int m,int k) {		//输入转化为无向图
	G->vN = n+m; G->eN = k;
	//G->V = new int*[m+n+1];
	for (int i = 1; i < G->vN+1; i++) {
		//G->V[i] = new int[m+n+1];
		for (int j = 1; j < G->vN + 1; j++) {
			G->V[i][j] = MAXSIZE;
		}
	}
	int v1, v2, w;
	char c1[5], c2[5];
	for (int i = 1; i < k + 1; i++) {
		cin >> c1;
		v1 = charToInt(c1);
		cin >> c2;
		v2 = charToInt(c2);
		cin >> w;
		Insert( v1, v2, w);
	};
}
int FindNextNode() {				//找到dist数组中未标记的最短距离顶点
	int min = MAXSIZE, next=-1;
	for (int i = 1; i < G->vN+1; i++) {
		if (visited[i] == 0 && min > dist[i]) {
			next = i;
			min = dist[i];
		}
	}
	return next;
}
void FindMinDist(int v) {	//核心算法:修改后的dijistra算法
	for (int i = 1; i < N + M + 1; i++) {		//外部数组初始化,非常重要!!!
		dist[i] = MAXSIZE; visited[i] = 0;
	}
	int v1 = v;				//v1用于遍历
	dist[v1] = 0; 
	while (v1 != -1) {				//开始循环,FindNextNode返回-1表示已无未标记可抵达节点,即当前连通分量已遍历完毕
		visited[v1] = 1;
		for(int i=1;i<G->vN+1;i++)					//遍历当前节点的全部邻接点,选择未标记顶点进行操作
		{					
			if ( G->V[v1][i]!=MAXSIZE&&visited[i]==0&& dist[i] > dist[v1] + G->V[v1][i]) {	//发现更短路径,更新dist、path、team、pathcount数组
				dist[i] = dist[v1] + G->V[v1][i];
			}													
		}
		v1 = FindNextNode();												//前往下一个未标记顶点,对应大循环
		
	}
}
void PrintFloat(float f) {
	cout<<fixed<<setprecision(1)<< f;
}
int main() {
	cin >> N>>M>>K>>D;
	Build(N, M, K);					//建立图				
	int maxmindist = 0, flag = 0, idealnode = 0;
	float avedist = 0, t = 0;
	for (int i = 1; i < M + 1; i++) {
		flag = 0;
		FindMinDist(i);			//执行最短路径算法
		int mindist = MAXSIZE, totaldist = 0;
		for (int i = M + 1; i < M + N + 1; i++) {
			if (dist[i] > D)
			{
				flag = 1;
				break;
			}
			totaldist += dist[i];
			if (dist[i] < mindist) mindist = dist[i];
		}
		if (flag == 1) continue;
		t = 1.0*totaldist / N;
		if (maxmindist < mindist) {
			maxmindist = mindist;
			avedist = t;
			idealnode = i;
		}
		else if (maxmindist == mindist && t < avedist) {
			avedist = t;
			idealnode = i;
		}
	}
	if (idealnode == 0) cout << "No Solution";
	else {
		cout << 'G' << idealnode << endl;
		PrintFloat(float(maxmindist));
		cout << " ";
		PrintFloat(avedist);
	}
	return 0;
}


发表于 2021-07-22 02:04:40 回复(0)
提供一个刚写好的Python版本,牛客Accepted,PAT除一个点超时外也可全部通过

from math import inf
from sys import stdin
from statistics import mean


resident, gas, road, range_max = map(int, input().split())
spot = resident + gas
graph = [ [inf] * (spot+1) for _ in range(spot+1) ]
result, far_max, avg_min = 0, -inf, 0

for line in stdin.readlines():
    v1, v2, length = line.split()
    length = int(length)
    v1 = int(v1[1:]) + resident if v1[0] == 'G' else int(v1)
    v2 = int(v2[1:]) + resident if v2[0] == 'G' else int(v2)
    if v1 == v2: length = 0
    if graph[v1][v2] != inf:
        length = min(length, graph[v1][v2])
    graph[v1][v2] = graph[v2][v1] = int(length)

def Dijkstra(source):
    dist, collected = [inf] * (spot+1), [False] * (spot+1)
    dist[source] = 0
    while True:
        v, dist_min = -1, inf
        for i in range(1, spot+1):
            if not collected[i] and dist[i] < dist_min:
                v = i
                dist_min = dist[i]
        if v == -1: break
        collected[v] = True

        for w in range(1, spot+1):
            if graph[v][w] != inf and not collected[w]:
                if dist[v] + graph[v][w] < dist[w]:
                    dist[w] = dist[v] + graph[v][w]
    return dist

for i in range(resident+1, spot+1):
    dist = Dijkstra(i)
    dist_min = inf
    for r in range(1, resident+1):
        if dist[r] > range_max:
            dist_min = -1
            break
        if dist[r] < dist_min:
            dist_min = dist[r]
    if dist_min == -1: continue
    dist_avg = mean( dist[1:resident+1] )
    if dist_min > far_max or (dist_min == far_max and dist_avg < avg_min):
        result = i - resident
        far_max = dist_min
        avg_min = dist_avg

if result:
    print('G{}\n{:.1f} {:.1f}'.format( result, far_max, avg_min ))
else:
    print('No Solution')

注:牛客一个测试点有误,输入225条边的数据,而原数据为255,故我直接用sys.stdin.readlines()读取数据行,规避该问题。


编辑于 2021-03-04 22:27:00 回复(0)
看着很复杂,实际上就是个最短路。。。
#include<iostream>
(720)#include<vector>
#include<string>
(765)#include<queue>
#include<limits.h>
(1124)#include<float.h>
using namespace std;
const int MAXN = 1011;
typedef pair<int, int> PP;
struct Edge {
	int to;
	int length;
	Edge(int to, int n) :to(to), length(n) {}
};
int N, M, K, DS, x;
vector<Edge>graph[MAXN];
int dist[MAXN];
double mmin = DBL_MIN;
int index = 11;
double aver = DBL_MAX;
void dijkstra(int source) {
	priority_queue<PP, vector<PP>,greater<PP> >myqueue;
	fill(dist, dist + MAXN, INT_MAX);
	dist[source] = 0;
	myqueue.push(PP(0, source));
	while (!myqueue.empty()) {
		int u = myqueue.top().second;
		myqueue.pop();
		for (int i = 0; i < graph[u].size(); i++) {
			int v = graph[u][i].to;
			int length = graph[u][i].length;
			if (dist[v] > dist[u] + length) {
				dist[v] = dist[u] + length;
				myqueue.push(PP(dist[v], v));//pair先比较first,因此把距离放在first
			}
		}
	}
	int tmp_index = source, sum = 0;
	double tmp_aver, tmp_min = DBL_MAX ;
	for (int i = M + 1; i <= N + M; i++) {
		sum += dist[i];
		if (dist[i] > DS) {
			return;
		}
		else if (dist[i] < tmp_min) {
			tmp_min = dist[i];
		}
	}
	tmp_aver = sum * 1.0 / N;
	if (tmp_min > mmin) {
		mmin = tmp_min;
		index = tmp_index;
		aver = tmp_aver;
	}
	else if (tmp_min == mmin && tmp_aver < aver) {
		mmin = tmp_min;
		index = tmp_index;
		aver = tmp_aver;
	}
	else if (tmp_min == mmin && tmp_aver == aver && tmp_index < index) {
		mmin = tmp_min;
		index = tmp_index;
		aver = tmp_aver;
	}
}
int main() {
	string s1, s2;
	cin >> N >> M >> K >> DS;
	for (int i = 0; i < K; i++) {
		int u, v;
		cin >> s1;
		cin >> s2;
		if (s1[0] == 'G') {
			s1.erase(0, 1);
			u = stoi(s1, 0, 10);
		}
		else {
			u = stoi(s1, 0, 10) + M;
		}
		if (s2[0] == 'G') {
			s2.erase(0, 1);
			v = stoi(s2, 0, 10);
		}
		else {
			v = stoi(s2, 0, 10) + M;
		}
		cin >> x;
		graph[u].push_back(Edge(v, x));
		graph[v].push_back(Edge(u, x));
	}
	for (int i = 1; i <= M; i++) {
		dijkstra(i);
	}
	if (index!=11) {
		cout << "G" << index << '\n';
		printf("%.1lf %.1lf", mmin, aver);
	}
	else {
		printf("No Solution");
	}

}


发表于 2020-03-20 12:43:47 回复(0)
注意:牛客网的输入可能有相同节点多次输入的情况,需要取最小。然后就用dijkstra算法就好了。
#include <iostream>
(720)#include <cstdio>
#include <string>
(765)#include <sstream>
#define INF 0x3f3f3f3f
using namespace std;
int N,M,K,Ds;
int T;
int graph[2000][2000];
bool used[2000];
int dis[2000];
void dijkstra(int s)
{
    fill(used,used+T,false);
    fill(dis,dis+T,INF);
    dis[s] = 0;
    while(1)
    {
        int v = -1;
        for(int u=1;u<T;u++)
        {
            if(!used[u]&&(v==-1||dis[u]<dis[v]))
                v=u;
        }
        if(v==-1)
            break;
        used[v] = true;
        for(int u=1;u<T;u++)
        {
            dis[u] = min(dis[u],dis[v]+graph[v][u]);
        }
    }
}
int main()
{
    scanf("%d%d%d%d",&N,&M,&K,&Ds);
    T = N+M+1;
    for(int i=0;i<=T;i++)
    {
        for(int j=0;j<=T;j++)
            graph[i][j] = INF;
    }
    for(int i=0;i<K;i++)
    {
        int a;
        int b;
        string str;
        cin>>str;
        if(str[0]=='G')
        {
            istringstream ss(str.substr(1,str.length()-1));
            ss>>a;
            a += N;
        }
        else{
            istringstream ss(str);
            ss>>a;
        }
        cin>>str;
        if(str[0]=='G')
        {
            istringstream ss(str.substr(1,str.length()-1));
            ss>>b;
            b += N;
        }
        else{
            istringstream ss(str);
            ss>>b;
        }
        int dis;
        //cout<<"input:"<<a<<" "<<b<<endl;
        scanf("%d",&dis);
        graph[a][b] = min(graph[a][b],dis);
        graph[b][a] = min(graph[b][a],dis);
    }
    int minisum=0;
    int maxi = -1;
    int ansind = 1;
    for(int i=1;i<=M;i++)
    {
        int sum=0;
        int mini = INF;
        dijkstra(i+N);
        bool out = false;
        for(int j=1;j<=N;j++)
        {
            if(dis[j]>Ds)
            {
                out = true;
                break;
            }
            if(dis[j]<mini)
            {
                mini = dis[j];
            }
            sum+=dis[j];
        }
        if(!out)
        {
            if(mini>maxi)
            {
                maxi = mini;
                minisum = sum;
                ansind = i;
            }
            else if(maxi==mini)
            {
                if(sum<minisum)
                {
                    minisum = sum;
                    ansind = i;
                }
            }
        }
    }
    if(maxi>0)
    {
        cout<<"G"<<ansind<<endl;
        printf("%.1lf %.1lf\n",double(maxi),double(minisum+1e-5)/N);
    }
    else cout<<"No Solution"<<endl;
    return 0;
}


发表于 2020-02-21 18:57:01 回复(1)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1020;
const int INF=1000000000;

int n,m,k,DS,G[MAXN][MAXN];
int d[MAXN];
bool vis[MAXN]={false};

void Dijkstra(int s){
	memset(vis,false,sizeof(vis));
	fill(d,d+MAXN,INF);
	d[s]=0;
	for(int i=0;i<n+m;i++){
		int u=-1,MIN=INF;
		for(int j=1;j<=n+m;j++){
			if(vis[j]==false&&d[j]<MIN){
				u=j;
				MIN=d[j];
			}
		}
		if(u==-1)return;
		vis[u]=true;
		for(int v=1;v<=n+m;v++){
			if(vis[v]==false&&G[u][v]!=INF){
				if(d[u]+G[u][v]<d[v]){
					d[v]=d[u]+G[u][v];
				} 
			}
		}
	}
}

int getID(char str[]){
	int i=0,len=strlen(str),ID=0;
	while(i<len){
		if(str[i]!='G'){
			ID=ID*10+(str[i]-'0');
		}
		i++;
	}
	if(str[0]=='G')return n+ID;
	else return ID;
}


int main(){
	scanf("%d%d%d%d",&n,&m,&k,&DS);
	int u,v,w;
	char city1[5],city2[5];
	fill(G[0],G[0]+MAXN*MAXN,INF);
	for(int i=0;i<k;i++){
		scanf("%s %s %d",city1,city2,&w);
		u=getID(city1);
		v=getID(city2);
		G[v][u]=G[u][v]=w;
	}
	double ansDis=-1,ansAvg=INF;
	int ansID=-1;
	for(int i=n+1;i<=n+m;i++){
		double minDis=INF,avg=0;
		Dijkstra(i);
		for(int j=1;j<=n;j++){
			if(d[j]>DS){
				minDis=-1;
				break;
			}
			if(d[j]<minDis)minDis=d[j];
			avg+=1.0*d[j]/n;
			
		}
		if(minDis==-1)continue;
		if(minDis>ansDis){
			ansID=i;
			ansDis=minDis;
			ansAvg=avg;
		}else if(minDis==ansDis&&avg<ansAvg){
			ansID=i;
			ansAvg=avg;
		}
	}
	if(ansID==-1)printf("No Solution\n");
	else{
		printf("G%d\n",ansID-n);
		printf("%.1f %.1f\n",ansDis,ansAvg);
	}
	return 0;
}

/*我哪里出错了呀

发表于 2020-02-19 08:41:40 回复(0)
//
//  main.cpp
//  1072 Gas Station (30分)
//
//  Created by Zide Liu on 2020/2/8.
//  Copyright © 2020 Zide Liu. All rights reserved.
//

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=1020;
const int INF=1000000000;
int n,m,k,DS,G[maxn][maxn];
int d[maxn];
bool vis[maxn]={false};
int getid(char str[]){
    unsigned long len=strlen(str);
    int ID=0,i=0;
    while(i<len){
        if(str[i]!='G'){
            ID=ID*10+(str[i]-'0');
        }
        i++;
    }
    if(str[0]=='G')return n+ID;
    else return ID;
}
void Dijkstra(int s){
    fill(vis,vis+maxn,false);
    fill(d,d+maxn,INF);
    d[s]=0;
    for(int i=0;i<n+m;i++){
        int u=-1,MIN=INF;
        for(int j=1;j<=n+m;j++){
            if(vis[j]==false&&d[j]<MIN){
                u=j;
                MIN=d[j];
            }
        }
        if(u==-1)return;
        vis[u]=true;
        for(int v=1;v<=n+m;v++){
            if(vis[v]==false&&G[u][v]!=INF){
                if(d[u]+G[u][v]<d[v]){
                    d[v]=d[u]+G[u][v];
                }
            }
        }
    }
}
int main(int argc, const char * argv[]) {
    scanf("%d%d%d%d",&n,&m,&k,&DS);
    int u,v,w;
    char city1[5],city2[5];
    fill(G[0],G[0]+maxn*maxn,INF);
    for(int i=0;i<k;i++){
        scanf("%s %s %d",city1,city2,&w);
        u=getid(city1);
        v=getid(city2);
        w=min(G[u][v],w);
        G[u][v]=G[v][u]=w;
    }
    double ansDis=-1,ansAvg=INF;
    int ansId=-1;
    for(int i=n+1;i<=n+m;i++){
        double minDis=INF,avg=0;
        Dijkstra(i);
        for(int j=1;j<=n;j++){
            if(d[j]>DS){
                minDis=-1;
                break;
            }
            if(d[j]<minDis)minDis=d[j];
            avg+=1.0*d[j]/n;
        }
        if(minDis==-1)continue;
        if(minDis>ansDis){
            ansDis=minDis;
            ansId=i;
            ansAvg=avg;
        }else if(minDis==ansDis&&avg<ansAvg){
            ansAvg=avg;
            ansId=i;
        }
    }
    if(ansId==-1)printf("No Solution\n");
    else{
        printf("G%d\n",ansId-n);
        printf("%.1f %.1f\n",ansDis,round(ansAvg*10)/10.0);
    }
    return 0;
}


最后的输入要注意,按照样例,这里应该是需要四舍五入的。
本题采用了Dijsktra算法,先用最短路径算法,对最短路径进行求解,然后对每个加油站进行计算其最大的最短距离,最小平均距离。
发表于 2020-02-08 20:42:48 回复(0)
这题目浪费了我茫茫多的时间。
1.第一眼没注意到M很小,第一时间想到floyd算法,但是PTA那里时限只有200ms最后一个测试点过不去,这里有1000ms,但我没试过。用dijkstra算法重写了一遍。
2.不知道stoi和istringstream什么毛病,在这里炸了,没有深究,改用sscanf。
3.我始终搞不懂它的be accurate up 1 decimal place指的是什么?究竟是直接丢弃小数点后两位之后的数还是要四舍五入,按以前的经验来说应该直接丢弃就可以了,但是这样子第一个样例输出的是G1 2.0 3.2不对,于是选择加上0.05,结果最后PTA那里最后一个测试点死活过不去。最终发现不加虽然过不了样例,但是能过所有测试点,我也是服了。
4.在线调试后发现,nowcoder这里的数据有自环,人与人之间基本的信任没了。

题目本身没什么说的,编码可以把可选加油站点编到0..M-1,耗死编到M..M+N,求出所有可选站点到所有耗死的最短路就可以了。
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <queue>
#include <exception>
#include <map>
#include <climits>
#define dbg(x) cout << #x ": " << (x) << endl
#define INF INT_MAX
#define mp make_pair
using namespace std;
using LL = long long;

const LL maxn = 1123;

struct Edge{
    int from, to, dist;
    Edge(int from, int to, int dist): from(from), to(to), dist(dist){}
};

bool operator <(const Edge& lhs, const Edge& rhs){
    return lhs.dist > rhs.dist;
}


int main(){
    int N, M, K, D;
    cin >> N >> M >> K >> D;
    vector<vector<Edge>> G(N + M);
    priority_queue<Edge> pq;
    map<pair<int, int>, int> roads;
    for(int i = 0; i < K; i++){
        string s1, s2;
        int p1, p2, dist;
        cin >> s1 >> s2 >> dist;
        if(s1[0] == 'G'){
            // istringstream ss(s1.substr(1));
            // ss >> p1;
            sscanf(s1.c_str() + 1, "%d", &p1);
            p1--;
        }
        else{
            // istringstream ss(s1);
            // ss >> p1;
            sscanf(s1.c_str(), "%d", &p1);
            p1 += M - 1;
        }
        if(s2[0] == 'G'){
            sscanf(s2.c_str() + 1, "%d", &p2);
            p2--;
        }
        else{
            sscanf(s2.c_str(), "%d", &p2);
            p2 += M - 1;
        }
        int a = min(p1, p2), b = max(p1, p2);
        if(a == b){
            // *(int*)0;
            // cout << "self loop!!!" << endl;
            // exit(0);
            continue;
        }
        if(roads.find(mp(a, b)) != roads.end()){
            if(roads[mp(a, b)] < dist){
                // while(true);
                // cout << "shorter path!!!" << endl;
                // exit(0);
                continue;
            }
        }
        G[p1].emplace_back(p1, p2, dist);
        G[p2].emplace_back(p2, p1, dist);
    }
    vector<vector<int>> dists(M, vector<int>(N + M, INF));
    for(int s = 0; s < M; s++){
        pq.emplace(s, s, 0);
        while(!pq.empty()){
            Edge e = pq.top(); pq.pop();
            int u = e.to;
            if(e.dist > dists[s][u]){
                continue;
            }
            dists[s][u] = e.dist;
            for(const auto& ne : G[u]){
                int v = ne.to;
                pq.emplace(s, v, e.dist + ne.dist);
            }
        }
    }
    int chosen = -1;
    double biggest_safe_dist = 0;
    double smallest_avg_dist = INF;
    for(int i = 0; i < M; i++){
        bool ok = true;
        int safe_dist = INF;
        double tot_dist = 0;
        for(int j = M; j < M + N; j++){
            if(dists[i][j] > D){
                ok = false;
                break;
            }
            safe_dist = min(dists[i][j], safe_dist);
            tot_dist += dists[i][j];
        }
        if(!ok) continue;
        double avg_dist = tot_dist / N;
        if(biggest_safe_dist < safe_dist){
            biggest_safe_dist = safe_dist;
            smallest_avg_dist = avg_dist;
            chosen = i;
        }
        else if(
            biggest_safe_dist == safe_dist
                && smallest_avg_dist > avg_dist
        ){
            smallest_avg_dist = avg_dist;
            chosen = i;
        }
    }
    if(chosen != -1){
        cout << "G" << chosen + 1 << endl;
        printf("%.1lf %.1f\n", biggest_safe_dist, smallest_avg_dist);
        // cout << fixed << setprecision(1);
        // cout << biggest_safe_dist + 0.05 << " " << smallest_avg_dist + 0.05 << endl;
        // cout << biggest_safe_dist << " " << smallest_avg_dist << endl;
    }
    else{
        cout << "No Solution" << endl;
    }
}


发表于 2019-09-03 23:42:03 回复(2)