HDU 2682 Tree
题目:
Problem Description
There are N (2<=N<=600) cities,each has a value of happiness,we consider two cities A and B whose value of happiness are VA and VB,if VA is a prime number,or VB is a prime number or (VA+VB) is a prime number,then they can be connected.What's more,the cost to connecte two cities is Min(Min(VA , VB),|VA-VB|).
Now we want to connecte all the cities together,and make the cost minimal.
Now we want to connecte all the cities together,and make the cost minimal.
Input
The first will contain a integer t,followed by t cases.
Each case begin with a integer N,then N integer Vi(0<=Vi<=1000000).
Each case begin with a integer N,then N integer Vi(0<=Vi<=1000000).
Output
If the all cities can be connected together,output the minimal cost,otherwise output "-1";
Sample Input
2
5
1
2
3
4
5
4
4
4
4
4
Sample Output
4 -1
- 最小生成树的应用
代码
1 #include <iostream> 2 #include <algorithm> 3 #include <cmath> 4 #include <cstring> 5 #define MAXN 600 6 #define Vi 1000000 7 using namespace std; 8 9 int pre[MAXN]; 10 int v[MAXN]; 11 int prime[Vi]; 12 13 struct node{ 14 int begin; 15 int end; 16 int cost; 17 }s[180000]; 18 19 bool cmp(node a, node b) 20 { 21 return a.cost < b.cost; 22 } 23 24 void init() 25 { 26 for(int i = 1; i <= MAXN; i++) 27 { 28 pre[i] = i; 29 } 30 } 31 32 int find(int x) //路径压缩 33 { 34 if(x != pre[x]) //从x结点搜索到根结点所经过的结点都指向该根结点 35 pre[x] = find(pre[x]); //回溯时的压缩路径 36 return pre[x]; 37 } 38 39 int kruskal(int cnt) 40 { 41 int mincost = 0; 42 sort(s, s + cnt, cmp); 43 for(int i = 0; i < cnt; i++) //判断边所对的两个结点是否属于同一根节点,不是则合并,计入边长 44 { 45 int fx = find(s[i].begin); 46 int fy = find(s[i].end); 47 if(fx != fy) 48 { 49 pre[fx] = fy; 50 mincost += s[i].cost; 51 } 52 } 53 return mincost; 54 } 55 56 void isprime() 57 { 58 memset(prime, 1, sizeof(prime)); //初始化认为所有数都为素数 59 prime[0] = prime[1] = 0; //0和1不是素数 60 for(int i = 2; i <= Vi; i++) 61 { 62 for(int j = i * 2; j <= Vi; j += i) //素数的倍数都为合数 63 { 64 prime[j]=0; 65 } 66 } 67 } 68 69 int main() 70 { 71 isprime(); 72 int n, t; 73 while(scanf("%d", &t) != EOF) 74 { 75 while(t--) 76 { 77 init(); //初始化成独立节点 78 scanf("%d", &n); //输入n个城市 79 for(int i = 1; i <= n; i++) 80 { 81 cin >> v[i]; //输入各城市的幸福值 82 } 83 int cnt = 0; 84 for(int i = 1; i <= n; i++) //记录符合连接条件的边数 85 { 86 for(int j = i + 1; j <= n; j++) 87 { 88 if(prime[v[i]] || prime[v[j]] || prime[v[i] + v[j]]) 89 { 90 s[cnt].begin = i; 91 s[cnt].end = j; 92 s[cnt].cost = min(min(v[i], v[j]), abs(v[i] - v[j])); 93 cnt++; 94 } 95 } 96 } 97 int mincost = kruskal(cnt); 98 int sum = 0; 99 for(int i = 1; i <= n; i++) 100 { 101 if(find(pre[i]) == i) 102 sum++; 103 } 104 if(sum != 1) 105 printf("-1\n"); 106 else 107 printf("%d\n", mincost); 108 } 109 } 110 return 0; 111 }
总结:
卡了我很久很久,燃烧了生命还是没有在昨晚的深夜里做出来,结果今儿一看……保存是否是素数的数组居然只开了600!!!一共在1000000个数里判断素数啊,当场死亡,我说怎么解决了TLE还一直WA。
不过,还是有值得的地方,学到了素数筛,判断素数快人一步~~ 以及使用并查集最好进行路径压缩,不然大概率TLE。
但是,有个WA还是没搞懂为啥WA,AC的代码只是在WA基础上删除了存储素数的几行代码而已(在我看来)。
WA代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <cmath> 4 #include <cstring> 5 #define MAXN 600 6 #define Vi 1000000 7 using namespace std; 8 9 int pre[MAXN]; 10 int v[MAXN]; 11 int su[MAXN]; 12 int prime[Vi]; 13 14 struct node{ 15 int begin; 16 int end; 17 int cost; 18 }s[180000]; 19 20 bool cmp(node a, node b) 21 { 22 return a.cost < b.cost; 23 } 24 25 void init() 26 { 27 for(int i = 1; i <= MAXN; i++) 28 { 29 pre[i] = i; 30 } 31 } 32 33 int find(int x) 34 { 35 if(x != pre[x]) 36 pre[x] = find(pre[x]); 37 return pre[x]; 38 } 39 40 int kruskal(int cnt) 41 { 42 int mincost = 0; 43 sort(s, s + cnt, cmp); 44 for(int i = 0; i < cnt; i++) 45 { 46 int fx = find(s[i].begin); 47 int fy = find(s[i].end); 48 if(fx != fy) 49 { 50 pre[fx] = fy; 51 mincost += s[i].cost; 52 } 53 } 54 return mincost; 55 } 56 57 void isprime() 58 { 59 int flag = 1; 60 memset(prime, 1, sizeof(prime)); //初始化认为所有数都为素数 61 prime[0] = prime[1] = 0; //0和1不是素数 62 for(int i = 2; i <= Vi; i++) 63 { 64 if(prime[i]) //保存素数 65 { 66 su[flag++] = i; 67 } 68 for(int j = i * 2; j <= Vi; j += i) //素数的倍数都为合数 69 { 70 prime[j]=0; 71 } 72 } 73 } 74 75 int main() 76 { 77 isprime(); 78 int n, t; 79 while(scanf("%d", &t) != EOF) 80 { 81 while(t--) 82 { 83 init(); 84 scanf("%d", &n); 85 for(int i = 1; i <= n; i++) 86 { 87 cin >> v[i]; 88 } 89 int cnt = 0; 90 for(int i = 1; i <= n; i++) 91 { 92 for(int j = i + 1; j <= n; j++) 93 { 94 if(prime[v[i]] || prime[v[j]] || prime[v[i] + v[j]]) 95 { 96 s[cnt].begin = i; 97 s[cnt].end = j; 98 s[cnt].cost = min(min(v[i], v[j]), abs(v[i] - v[j])); 99 cnt++; 100 } 101 } 102 } 103 int mincost = kruskal(cnt); 104 int sum = 0; 105 for(int i = 1; i <= n; i++) 106 { 107 if(find(pre[i]) == i) 108 sum++; 109 } 110 if(sum != 1) 111 printf("-1\n"); 112 else 113 printf("%d\n", mincost); 114 } 115 } 116 return 0; 117 }
WA代码后记:
数组su[]开小了,虽然用不到,但是因为太小了后续存储不够用,程序运行时为了存储就会随便找个地方存,这就产生了与之前存过的变量发生冲突的可能性,也就是使原本正确的数据被覆盖成错误信息导致WA。
果然还是太菜了,还得多多向学长学习,请教问题。