HDU2682 Tree

来源:互联网 发布:怎么申请开通80端口 编辑:程序博客网 时间:2024/06/15 23:45

Tree

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2676    Accepted Submission(s): 830


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
251234544444
 

Sample Output
4-1

题意:图中有n个点,每个点都有一个值。如果两个点a, b之间满足a或者b或者a+b是素数,那么这两个点之间有一条路径,路径的权值为min(min(a, b), |a-b|)。求最小生成树。

解析:最小生成树问题,用prim和Kruskal都行,不过需要根据给定的点的值进行预处理建图。

代码(prime):

#include <cstdio>#include <cstdlib>#include <algorithm>#include <queue>#include <cstring>#include <cmath>using namespace std;#define N 605#define INF 1000000000typedef long long ll;ll mp[N][N], vi[N], dis[N];bool vis[N];bool tag[2000005];int n;void Prime()  {      memset(tag,0,sizeof(tag));      tag[0]=tag[1]=1;      for(int i=2; i*i <= 2000001; i++)          if(tag[i]==0){               for(int j=i+i;j<=2000001;j+=i)                  tag[j]=1;          }  }  ll Prim(){for(int i = 0; i < n; i++){dis[i] = mp[0][i];vis[i] = false;}int st = 0;ll ans = 0;dis[st] = 0;vis[st] = true;int ct = n - 1, flag = 1;while(ct && flag){ct--;int Min = INF;flag = 0;for(int i = 0; i < n; i++){if(!vis[i] && Min > dis[i]){Min = dis[i];st = i;flag = 1;}}ans += Min;vis[st] = true;for(int i = 0; i < n; i++){if(st == i)continue;if(!vis[i] && dis[i] > mp[st][i])dis[i] = mp[st][i];}}if(flag == 0)return -1;return ans;} int main(){int t;scanf("%d", &t);Prime();while(t--){scanf("%d", &n);for(int i = 0; i < n; i++)scanf("%lld", &vi[i]);for(int i = 0; i < n; i++){for(int j = i; j < n; j++){if(i == j)mp[i][j] = 0;else if(!tag[vi[i]] || !tag[vi[j]] || !tag[vi[i]+vi[j]])mp[i][j] = mp[j][i] = min(min(vi[i], vi[j]), abs(vi[i]-vi[j]));elsemp[i][j] = mp[j][i] = INF;}}ll ans = Prim();printf("%lld\n", ans);}return 0;}
代码(Kruskal):

#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>using namespace std;#define N 605#define INF 1000000000typedef long long ll;struct node{int start, end;ll len;bool operator < (const node &a)const{return len < a.len;}};node Edge[N*N/2];ll  vi[N], dis[N];bool tag[2000005];int n, ecnt;int father[N];void Prime()  {      memset(tag,0,sizeof(tag));      tag[0]=tag[1]=1;      for(int i=2; i*i <= 2000001; i++)          if(tag[i]==0){               for(int j=i+i;j<=2000001;j+=i)                  tag[j]=1;          }  }  int getFather(int x){return x == father[x]? x : father[x] = getFather(father[x]);}bool Join(int a, int b){int fa = getFather(a);int fb = getFather(b);if(fa != fb){father[fa] = fb;return true;}return false;}ll Kruskal(){for(int i = 0; i < n; i++){father[i] = i;}ll ans = 0;int cnt = n - 1;for(int i = 0; i < ecnt; i++){if(Join(Edge[i].start, Edge[i].end)){cnt--;ans += Edge[i].len;}}if(cnt > 0)return -1;return ans;}int main(){int t;node p;scanf("%d", &t);Prime();while(t--){scanf("%d", &n);ecnt = 0;for(int i = 0; i < n; i++)scanf("%lld", &vi[i]);for(int i = 0; i < n; i++){for(int j = i; j < n; j++){if(i == j)continue;if(!tag[vi[i]] || !tag[vi[j]] || !tag[vi[i]+vi[j]]){ll len = min(min(vi[i], vi[j]), abs(vi[i]-vi[j]));Edge[ecnt].start = i, Edge[ecnt].end = j, Edge[ecnt++].len = len;}}}sort(Edge, Edge+ecnt);ll ans = Kruskal();printf("%lld\n", ans);}return 0;}
因为这个图可能存在多个集合之间没有路径,即不存在最小生成树,需要判断。


原创粉丝点击