CCF 201903-5 317号子任务(60分)

前言

本文为CCF201903-5的思考
2019.9.3.1:00 洗完澡突然意识到自己前面都优化了行星发动机数组,后面居然没用,白白浪费了,然后改一下提交就60分了。
在这里插入图片描述

题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

思路对于学算法的来说应该很清晰,难点是怎么写出不超时的程序得满分,如果你对思路不清晰,还请继续学习下算法。
说来,本题就是求出每个顶点到行星基地的最短路径,然后在这些最短路径里选择最短的k个累加起来输出,完成的重点在于怎么找到这些最短路径,本文最后实现的代码只拿到了30分,还是超时了,有需要的可以参考,我会继续想办法优化实现代码,会优化或者有其他思路的也欢迎留言讨论。
在这里插入图片描述

SPFA实现代码

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<algorithm>
using namespace std;

const int MAXV = 10010;
const int INF = 1000000000;
struct node{
	int v;
	int w;
	node(int _v,int _w): v(_v),w(_w){};
};
int n,m,k,flag[MAXV],u,v,w,num[MAXV];
bool inq[MAXV];
vector<node> Adj[MAXV];
int d[MAXV];

bool cmp(int a,int b){
	return a<b;
}
bool SPFA(int s){
	memset(inq,false,sizeof(inq));
	memset(num,0,sizeof(num));
	fill(d,d+MAXV,INF);
	
	queue<int> q;
	q.push(s);
	inq[s] = true;
	num[s]++;
	d[s] = 0;
	while(!q.empty()){
		int u = q.front();
		q.pop();
		inq[u] = false;
		for(int j = 0;j<Adj[u].size();j++){
			int v = Adj[u][j].v;
			int w = Adj[u][j].w;
			if(d[u]+w<d[v]){
				d[v] = d[u]+w;
				if(!inq[v]){
					q.push(v);
					inq[v] = true;
					num[v]++;
					if(num[v]>=n) return false;
				}
			}
		}
	}
	return true;
}
int main(){
	vector<int> a;
	scanf("%d%d%d",&n,&m,&k);
	for(int i = 1;i<=n;i++){
		scanf("%d",&flag[i]);
	}
	for(int i = 0;i<m;i++){
		scanf("%d%d%d",&u,&v,&w);
		Adj[u].push_back(node(v,w));
		Adj[v].push_back(node(u,w));
	}
	for(int i = 1;i<=n;i++){
		priority_queue<int,vector<int>,greater<int> > a;
		int ans = 0;
		SPFA(i);
		for(int j = 1;j<=n;j++){
			if(flag[j] == 1&&d[j]!=INF){
				a.push(d[j]);
			}
		}
		for(int nums = 0;nums<k;nums++){
			if(!a.empty()){
				ans += a.top();
				a.pop();
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

改进

经过一点改进,只寻找行星节点的最短路径,因为从行星顶点到某个顶点的最短路径同时也是那个顶点到行星顶点的最短路径,需要用一个二维数组类似邻接矩阵来存储两顶点的距离,例如d[i][j]表示顶点i到顶点j的最短路径距离,所以可以减少一定的运行时间,最后提交代码得了35分。(能拿一点是一点)
在这里插入图片描述

代码实现

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<algorithm>
using namespace std;

const int MAXV = 10010;
const int INF = 1000000000;
struct node{
	int v;
	int w;
	node(int _v,int _w): v(_v),w(_w){};
};
int n,m,k,flag[MAXV],u,v,w,num[MAXV];
bool inq[MAXV];
vector<node> Adj[MAXV];
int d[MAXV][MAXV];

bool cmp(int a,int b){
	return a<b;
}
bool SPFA(int s){
	memset(inq,false,sizeof(inq));
	memset(num,0,sizeof(num));
	
	queue<int> q;
	q.push(s);
	inq[s] = true;
	num[s]++;
	d[s][s] = 0;
	while(!q.empty()){
		int u = q.front();
		q.pop();
		inq[u] = false;
		for(int j = 0;j<Adj[u].size();j++){
			int v = Adj[u][j].v;
			int w = Adj[u][j].w;
			if(d[s][u]+w<d[s][v]){
				d[s][v] = d[s][u]+w;
				if(!inq[v]){
					q.push(v);
					inq[v] = true;
					num[v]++;
					if(num[v]>=n) return false;
				}
			}
		}
	}
	return true;
}
int main(){
	int start[MAXV],t=0;
	scanf("%d%d%d",&n,&m,&k);
	for(int i = 1;i<=n;i++){
		scanf("%d",&flag[i]);
		if(flag[i]==1) start[t++]=i;
	}
	for(int i = 0;i<m;i++){
		scanf("%d%d%d",&u,&v,&w);
		Adj[u].push_back(node(v,w));
		Adj[v].push_back(node(u,w));
	}
	fill(d[0],d[0]+MAXV*MAXV,INF);
	for(int i = 0;i<t;i++){
		SPFA(start[i]);
	}
	for(int i = 1;i<=n;i++){
		priority_queue<int,vector<int>,greater<int> > a;
		int ans = 0;
		if(flag[i] == 1){
			for(int j = 1;j<=n;j++){
				if(flag[j]==1&&d[i][j]!=INF){
				    a.push(d[i][j]);
				}
			}
			for(int nums = 0;nums<k;nums++){
			    if(!a.empty()){
				    ans += a.top();
				    a.pop();
			    }
		    }
		    printf("%d\n",ans);
		}else{
			for(int j = 1;j<=n;j++){
				if(flag[j] == 1&&d[j][i]!=INF){
					a.push(d[j][i]);
				}
			}
			for(int nums = 0;nums<k;nums++){
			    if(!a.empty()){
				    ans += a.top();
				    a.pop();
			    }
		    }
		    printf("%d\n",ans);
		}	
	}
	return 0;
}

持续更新优化

跟前文的区别只在于用上了优化后的行星发动机数组,在遍历输出时不用O(V^2)的时间复杂度,只需要O(VK),所以通过了60%的测试点。
此处只粘贴了跟前文区别的地方,也即是最后输出时的一个大for循环。

for(int i = 1;i<=n;i++){
		priority_queue<int,vector<int>,greater<int> > a;
		int ans = 0;
		if(flag[i] == 1){
			for(int j = 0;j<t;j++){
				if(d[i][start[j]]!=INF){
				    a.push(d[i][start[j]]);
				}
			}
			for(int nums = 0;nums<k;nums++){
			    if(!a.empty()){
				    ans += a.top();
				    a.pop();
			    }
		    }
		    printf("%d\n",ans);
		}else{
			for(int j = 0;j<t;j++){
				if(d[start[j]][i]!=INF){
					a.push(d[start[j]][i]);
				}
			}
			for(int nums = 0;nums<k;nums++){
			    if(!a.empty()){
				    ans += a.top();
				    a.pop();
			    }
		    }
		    printf("%d\n",ans);
		}	
	}

总结

光学算法只能解决问题,怎么更好地解决问题还有学会选择合适的算法和学会优化。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值