您的位置:首页 > 其它

新疆大学(新大)OJ xju 1009: 一带一路 prim求最短路径+O(n)素数筛选

2017-10-19 22:34 399 查看
1009: 一带一路

时间限制: 1 Sec 内存限制: 128 MB

提交: 121 解决: 22

[提交][状态][讨论版]

题目描述

一带一路是去去年习大大提出来的建设“新丝绸之路经济带”和“21世纪海上丝绸之路”的战略构想。其中就包括我们新疆乌鲁木齐,所以这也是对新疆来说是一个巨大的机遇。我们新疆要加强和周边国家的经济文化交流,就必然要和周边国家城市修许多路。现在假设有N座城市,每一个城市都有一个投资指标数,例如A城市和B城市的投资指标数分别为Ia和Ib,如果Ia或Ib或Ia-Ib的绝对值为素数或者为1,则A城市和B城市可以修路,否则不能。他们修路的花费为Ia,Ib,Ia-Ib的绝对值这三个数中的最小值,并且为素数或者1。现在已知所以城市之间的投资指标,假设他们直接原来没有任何路,要求你在其中修路联通这些城市(即任何两座城市之间都能直接或者间接的有路相通)。求修这些路最少花费总和。

输入

输入包含多组数据,第一行为测试数据T组(1<=T<=10);以下每组数据第一行包含城市的个数N(1

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;

int a[110];

int s[110][110];  //邻接矩阵

//O(n)的素数筛选,见小红书算法与实现
int ans[1000010]; //按顺序记录素数
bool valid[1000010]; // valid[i] == true 表示 i是素数
int tot = 0;   //素数的个数
void getPrime(int n){
memset(valid,true,sizeof(valid));

for(int i = 2;i <= n; i++){
if(valid[i]){
tot++;ans[tot] = i;
}
for(int j = 1;((j <= tot)&&(i*ans[j] <= n)); j++){
valid[i*ans[j]] = false;
if(i&ans[j] == 0) break;
}
}
}

int mincost[110]; //记录从源点0到点i的最小花费
bool used[110];   // 记录i点是否使用过

int prim(int n){
for(int i = 0;i < n; i++){
mincost[i] = 2e9;
used[i] = false;
}
mincost[0] = 0;
int res = 0;
while(true){
int v = -1;
for(int u = 0;u < n; u++){
if(!used[u] && (v == -1 || mincost[u] < mincost[v])) v = u;
}
if(v == -1||mincost[v] == 2e9) break;
used[v] = true;
res += mincost[v];
for(int u = 0;u < n; u++){
mincost[u] = min(mincost[u],s[v][u]);
}
}
//判断是否有点没有用过,即不能产生最小生成树
int flag = 0;
for(int i = 0;i < n; i++){
if(!used[i]){
flag = 1;
break;
}
}
if(flag) return -1;
if(res <= 0) return -1;
return res;
}

int main()  {

//O(n)的素数筛选
getPrime(1000001);
int t,n;
cin >> t;

int num = 0;

while(t--){
for(int i = 0;i < 101; i++){
for(int j = 0;j < 101; j++){
s[i][j] = 2e9;
}
}
cin >> n;
for(int i = 0;i < n; i++){
cin >> a[i];
}
for(int i = 0;i < n; i++){
for(int j = i+1;j < n; j++){

//找到3个数中最小的素数
int p = abs(a[i]-a[j]);
int d[3] = {p,a[i],a[j]};
sort(d,d+3);
for(int k = 0;k < 3; k++){
if(valid[d[k]]){
//如果为素数则跳出,此时是最小的素数
s[i][j] = d[k];
s[j][i] = d[k];
break;
}
}
//没有素数,即不产生一条边
if(s[i][j] == 0) s[i][j] = 2e9;
}
}

cout << "Case " << ++num << ": ";
cout << prim(n) << endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: