ccf csp 201903-5 317号任务

这道题数据规模太大,总是超时。求大佬给100分代码,实在不知道怎么改进。

我的解题思路是对每个点进行一次Dijkstra算法,找出符合要求的最近的点。

#include<iostream>
#include<cstring> 
#include<vector>
#include<queue>
const int INF = 1005;//最大弧长,相当于定义无限大 
const int MAXN = 10005;//顶点的最大数量 
using namespace std;
struct Edge{
 int from, to, dist;//dist是权值 
 Edge(int u, int v, int d):from(u),to(v),dist(d){}
};
struct HeapNode{
 int d;//距离
 int u;//弧的编号
 bool operator < (const HeapNode& rhs) const {
  return d > rhs.d;
 } 
};
struct Dijkstra{
 int n;//顶点的个数 
 int m;//边的个数
 int k;//需要找的行星发动机据点的个数 
 vector<Edge> edges;
 vector<int> G[MAXN];
 int is_star[MAXN]; //标志是否为行星发动机据点
  
 vector<int> fine_star;//保存已经找到的行星发送机据点 
 bool done[MAXN];    //是否已永久标号 
 int d[MAXN];        //原点s到各个点的最短距离 
 int p[MAXN];        //最短路径中的上一条弧
 
 void init(int n, int k){
  memset(is_star, 0, sizeof(is_star));
  this->n = n;
  this->k = k;
  for(int i=0;i<n;i++) G[i].clear();
  edges.clear();
 } 
 void addEdge(int from, int to, int dist){
  edges.push_back(Edge(from, to, dist));
  m = edges.size();
  G[from].push_back(m-1);
 }
 void dijkstra(int s) {
  //重置 
  for(int i=0;i<n;i++) d[i] = INF;
  fine_star.clear();
  d[s] = 0;
  memset(done, 0, sizeof(done));
  //计算 
  priority_queue<HeapNode> Q;
  Q.push((HeapNode){0,s});
  while(!Q.empty()) {
   HeapNode x = Q.top(); Q.pop();
   int u = x.u;
   if(done[u]) continue;
   done[u] = true;
   for(int i=0;i<G[u].size(); i++){
    Edge& e = edges[G[u][i]];
    if(d[e.to] > d[u] + e.dist) {
     d[e.to] = d[u] + e.dist;
     p[e.to] = G[u][i];
     Q.push((HeapNode){d[e.to], e.to});
    }
   }
   if(is_star[u]){
    fine_star.push_back(u);
    if(fine_star.size()==k) return;
   }
  }
 }
 int solve(int s){
  dijkstra(s);
  int sum=0;
  for(int i=0;i<fine_star.size();i++){
   sum += d[fine_star[i]];
  }
  return sum;
 }
};
void read_edges(Dijkstra& D, int m){
 int a,b,w;
 int n = D.n;
 vector<vector<int> > v(n, vector<int>(n, INF));
 for(int i=0;i<m;i++){
  cin>>a>>b>>w;
  a--;
  b--;
  if(a==b) continue;
  if(v[a][b]>w){
   v[a][b]=w;
   v[b][a]=w;
   D.addEdge(a,b,w);
   D.addEdge(b,a,w);
  }
 }
}
int main(){
 ios::sync_with_stdio(false);
 int n,m,k;
 cin>>n>>m>>k;
 Dijkstra D;
 D.init(n,k);
 for(int i=0;i<n;i++) cin>>D.is_star[i];
 read_edges(D, m);
 for(int i=0;i<n;i++){
  cout<<D.solve(i)<<endl;
 }
 return 0;
}

结果超时了,后来想到,所有的边其实都是无向边,两个点之间的最短距离其实只用算一遍。所以可以保存,减少计算量。

#include<iostream>
#include<cstring> 
#include<vector>
#include<queue>
const int INF = 1005;//最大弧长,相当于定义无限大 
const int MAXN = 10005;//顶点的最大数量 
using namespace std;
struct Edge{
 int from, to, dist;//dist是权值 
 Edge(int u, int v, int d):from(u),to(v),dist(d){}
};
struct HeapNode{
 int d;//距离
 int u;//弧的编号
 bool operator < (const HeapNode& rhs) const {
  return d > rhs.d;
 } 
};
struct Dijkstra{
 int n;//顶点的个数 
 int m;//边的个数
 int k;//需要找的行星发动机据点的个数 
 vector<Edge> edges;
 vector<int> G[MAXN];
 int is_star[MAXN]; //标志是否为行星发动机据点
  
 vector<int> fine_star;//保存已经找到的行星发送机据点 
 bool done[MAXN];    //是否已永久标号 
 vector<vector<int> > d;     //原点s到各个点的最短距离 
 //int p[MAXN][MAXN];        //最短路径中的上一条弧
 
 void init(int n, int k){
  memset(is_star, 0, sizeof(is_star));
  this->n = n;
  this->k = k;
  for(int i=0;i<n;i++) G[i].clear();
  edges.clear();
  d.resize(n);
  for(int i=0;i<n;i++){
   d[i].resize(n, INF);
  }
 } 
 void addEdge(int from, int to, int dist){
  edges.push_back(Edge(from, to, dist));
  m = edges.size();
  G[from].push_back(m-1);
 }
 void dijkstra(int s) {
  //重置 
  fine_star.clear();
  d[s][s] = 0;
  memset(done, 0, sizeof(done));
  //计算 
  priority_queue<HeapNode> Q;
  Q.push((HeapNode){0,s});
  while(!Q.empty()) {
   HeapNode x = Q.top(); Q.pop();
   int u = x.u;
   if(done[u]) continue;
   done[u] = true;
   for(int i=0;i<G[u].size(); i++){
    Edge& e = edges[G[u][i]];
    if(d[s][e.to] > d[s][u] + e.dist) {
     d[s][e.to] = d[s][u] + e.dist;
     d[e.to][s] = d[s][e.to];
     //p[e.to] = G[u][i];
     Q.push((HeapNode){d[s][e.to], e.to});
    }
    else if(d[s][e.to] < INF && e.to<s){
     Q.push((HeapNode){d[s][e.to], e.to});
    }
   }
   if(is_star[u]){
    fine_star.push_back(u);
    if(fine_star.size()==k) return;
   }
  }
 }
 void solve(){
  for(int i=0;i<n;i++){
   dijkstra(i);
   int sum=0;
   for(int j=0;j<fine_star.size();j++){
    sum += d[i][fine_star[j]];
   }
   cout<<sum<<endl;
  }
 }
};
void read_edges(Dijkstra& D, int m){
 int a,b,w;
 int n = D.n;
 vector<vector<int> > v(n, vector<int>(n, INF));
 for(int i=0;i<m;i++){
  cin>>a>>b>>w;
  a--;
  b--;
  if(a==b) continue;
  if(v[a][b]>w){
   v[a][b]=w;
   v[b][a]=w;
   D.addEdge(a,b,w);
   D.addEdge(b,a,w);
  }
 }
}

int main(){
 ios::sync_with_stdio(false);
 int n,m,k;
 cin>>n>>m>>k;
 Dijkstra D;
 D.init(n,k);
 for(int i=0;i<n;i++) cin>>D.is_star[i];
 read_edges(D, m);
 D.solve();
 return 0;
}

结果还是超时,只有30分。
应该还有更好的算法,精力有限,求助各位大佬。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值