A1072和A1087 数据不大、用的邻接矩阵

A1072跳转题目

一、题目大意

给你n个普通地点, m个可能设为加油站的地点,求m中能同时覆盖所有普通地点(到所有普通地点的最大距离不超过加油站的服务距离)的编号,有多个就按照到普通地点的最小距离较大、到所有普通地点的平均距离较小,较小编号排序选最优

二、分析

(1)通过第一个样例我们能看出来,n、m要一起跑最短路,但是计算m中可能为加油站的点x时,只用求x对1~n的距离

(2)输入中带有G1、G2这种的, 所以需要特殊处理,使n + 1号点表示G1、n + 2号点表示G2

(3)最终精确到小数点后1位不用+0.05直接.1lf就行,要不然最后一个测试点过不了,样例挺恶心的,我也是看了别人题解才知道这一点

三、代码

#include <bits/stdc++.h>

#define int long long
#define all(x) (x).begin(), (x).end()
#define len(x) (x).size()
#define endl '\n'
#define lowbit(x) ((x) & - (x))

//using namespace std;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int path[1111][1111];

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    //std::cout.precision(10);
    int n, m, k, max;
    std::cin >> n >> m >> k >> max;
    memset(path, 0x3f, sizeof(path));
    for(int i = 1; i <= n + m; i++)
        path[i][i] = 0;//初始化自身距离,防止后续数据有锅出现自环

    //后续节点我们都采用字符串输入,所以预处理一下对应的节点编号
    std::map<std::string, int> find;
    for(int i = 1; i <= n; i++) {
        std::string s = "";
        s += std::to_string(i);
        find[s] = i;
    }
    for(int i = n + 1; i <= m + n; i++) {
        std::string s = "G";
        s += std::to_string(i - n);
        find[s] = i;// G1对应n + 1
    }


    for(int i = 1; i <= k; i++) {
        std::string u, v;
        int x;
        std::cin >> u >> v >> x;
        path[find[u]][find[v]] = std::min(x, path[find[u]][find[v]]);
        path[find[v]][find[u]] = std::min(x, path[find[v]][find[u]]);
    }
    
    struct Gas {
        int id;
        double min;
        double avg;
        bool operator < (const Gas temp) {//设置排序规则
            if(this->min == temp.min && this->avg == temp.avg)
                return this->id < temp.id;
            if(this->min == temp.min)
                return this->avg < temp.avg;
            return this->min > temp.min;
        }
    };
    std::vector<Gas> v;

    auto dij = [&](int start) {//求start到其他所有点的最短路
        std::vector<int> dist(n + m + 1, 0x3f3f3f3f), flag(n + m + 1, 0);
        std::priority_queue<
        std::pair<int, int>,
        std::vector<std::pair<int, int>>,
        std::greater<std::pair<int, int>>
        > heap;//这里采用的是堆优化的dij,所以开个小根堆
        //下面就是dij的板子
        dist[start] = 0;
        heap.push({0, start});
        while(len(heap)) {
            auto t = heap.top();
            heap.pop();
            int root = t.second;
            int dis = t.first;
            if(flag[root]) 
                continue;
            flag[root] = 1;
            for(int i = 1; i <= n + m; i++) {
                if(i == root)
                    continue;
                if(path[root][i] == 0x3f3f3f3f)
                    continue;
                if(dist[i] > dist[root] + path[root][i]) {
                    dist[i] = dist[root] + path[root][i];
                    heap.push({dist[i], i});
                }
            }
        }
        double sum = 0;
        double min = 0x3f3f3f3f;
        int ok = 1;
        for(int i = 1; i <= n; i++) {
            if(dist[i] > max)
                ok = 0;
            sum += dist[i];
            min = std::min(min, dist[i] * 1.0);
        }
        if(ok) {//满足能覆盖所有普通点的可能点都记录下来
            sum /= n;
            Gas gas;
            gas.id = start;
            gas.min = min;
            gas.avg = sum;
            v.push_back(gas);
        }
    };

    for(int i = n + 1; i <= m + n; i++) {//对m个可能点跑dij
        dij(i);
    }
    if(len(v) == 0) {
        std::cout << "No Solution";
    } else {
        std::sort(all(v));//排序取最优
        printf("G%lld\n%.1lf %.1lf", v[0].id - n, v[0].min, v[0].avg);
    }

    return 0;
}

A1082跳转题目

一、题目大意

求起点到终点的最短距离的路径数、最短路径的大小、最大幸福值(路径点权和)、除起点的平均幸福值大小(向下取整),整个路径

二、分析

这题比较缝合,要处理输入,把字符串给离散化成整数编号,last维护到起点当前节点的上一节点,sum维护起点到当前节点的路径点权和,cnt维护起点到当前点的路径条数

三、代码

#include <bits/stdc++.h>

#define int long long
#define all(x) (x).begin(), (x).end()
#define len(x) (x).size()
#define endl '\n'
#define lowbit(x) ((x) & - (x))

//using namespace std;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int path[500][500];
signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    //std::cout.precision(10);
    std::map<std::string, int> find;//查找城市对应的节点编号
    std::map<int, std::string> hash;//查找节点编号对应的城市
    memset(path, 0x3f, sizeof(path));
    int n, m;
    std::cin >> n >> m;
    for(int i = 1; i <= n; i++)
    	path[i][i] = 0;
    std::vector<int> vue(n + 1);//存储幸福值
    std::string st;
    std::cin >> st;
    find[st] = 1;
    hash[1] = st;
    vue[1] = 0;
    for(int i = 2; i <= n; i++) {
    	std::string s;
    	std::cin >> s;
    	int x;
    	std::cin >> x;
    	find[s] = i;
    	hash[i] = s;
    	vue[i] = x;
    }
    for(int i = 1; i <= m; i++) {
    	std::string u, v;
    	int x;
    	std::cin >> u >> v >> x;
    	path[find[u]][find[v]] = std::min(x, path[find[u]][find[v]]);
    	path[find[v]][find[u]] = std::min(x, path[find[v]][find[u]]);
    }
    auto dij = [&](int start) {
    	std::vector<int> dist(n + 1, 0x3f3f3f3f), flag(n + 1, 0), cnt(n + 1, 0), sum(n + 1, 0), last(n + 1, 0);
    	std::priority_queue<
    	std::pair<int, int>,
    	std::vector<std::pair<int, int>>,
    	std::greater<std::pair<int, int>>
    	> heap;
        初始化起点
    	dist[start] = 0;
    	cnt[start] = 1;
    	sum[start] = 0;
    	last[start] = -1;
    	heap.push({0, start});

    	while(len(heap)) {
    		auto t = heap.top();
    		heap.pop();
    		int root = t.second;
    		int res = t.first;
    		if(flag[root])
    			continue;
    		flag[root] = 1;
    		for(int i = 1; i <= n; i++) {
    			if(i == root)
    				continue;
    			if(path[root][i] == 0x3f3f3f3f)
    				continue;
    			if(dist[i] > dist[root] + path[root][i]) {//起点到当前点的最短路被更新
    				dist[i] = dist[root] + path[root][i];
    				cnt[i] = cnt[root];//继承root的路径条数
    				sum[i] = sum[root] + vue[i];//重置当前点的幸福感
    				last[i] = root;//当前点的上一节点为root
    				heap.push({dist[i], i});
    			} else if(dist[i] == dist[root] + path[root][i]) {//出现最短路大小相同的路径
    				cnt[i] += cnt[root];//那么到当前点的路径条数就增加cnt[root]条
    				if(sum[i] < sum[root] + vue[i]) {//能从这个root获得更大的幸福感
    					sum[i] = sum[root] + vue[i];
    					last[i] = root;//那么就让当前点从这个root过来
    				}
    			}
    		}
    	}
    	std::string end = "ROM";
    	std::vector<int> v;
    	for(int i = find[end]; i != -1; i = last[i]) {//回溯路径
    		v.push_back(i);
    	}
    	int ans = sum[find[end]] / (len(v) - 1);
    	std::cout << cnt[find[end]] << " " << dist[find[end]] << " " << sum[find[end]] << ' ' << ans << endl;
    	for(int i = len(v) - 1; i >= 0; i--) {
    		std::cout << hash[v[i]];
    		if(i != 0)
    			std::cout << "->";
    	}
    };
    dij(find[st]);

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值