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.
 

 

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).
 

 

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。

    果然还是太菜了,还得多多向学长学习,请教问题。

 

posted @ 2019-07-07 17:25  Anzer  阅读(166)  评论(0编辑  收藏  举报