这道题数据规模太大,总是超时。求大佬给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分。
应该还有更好的算法,精力有限,求助各位大佬。