文章标题 HDU 2686 : Tree (最小生成树+普通筛)

来源:互联网 发布:阿里云总裁 编辑:程序博客网 时间:2024/06/05 16:46

Tree

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
题意:有n个点,每个点有一个权值,然后如果两个点a,b之间有连边当a、b、a+b中至少存在一个是素数,如果能连边,边的权值为 Min(Min(VA , VB),|VA-VB|),即a、b、|a+b|中的最小值,然后要我们求这n个的最小生成树,如果没法形成生成树就输出-1。
分析:先预处理出200000内的素数,然后对于任意两个点看是否能连边。然后跑一下kurskal就行了。
代码:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <queue>#include <set>#include <map>#include <algorithm>#include <math.h>#include <vector>using namespace std;int n; struct node {    int u,v,w;    bool operator <(const node &t)const {        return w<t.w;    }}edge[605*605];//边集 int fa[1000006];//并查集 bool prime[2000005];//标记是否是素数 int a[605];int find(int x){//并查集     return fa[x]==x?x:fa[x]=find(fa[x]);}void getprime(){//预处理出素数     memset (prime,true,sizeof (prime));    prime[0]=prime[1]=false;    for (int i=2;i<=2000000;i++){        if (prime[i]){            for (int j=i*2;j<=2000000;j+=i){                prime[j]=false;            }        }    }} int judge(int a,int b){//判断是否能连边     if (prime[a]||prime[b]||prime[a+b]){        return min((int)fabs(a-b),min(a,b));    }    return -1;//不能连边直接输出-1 }int main(){    getprime();//预处理     int T;    scanf ("%d",&T);    while (T--){        scanf ("%d",&n);        for (int i=0;i<n;i++){            scanf ("%d",&a[i]);        }        for (int i=0;i<=1000000;i++)fa[i]=i;//初始化         int cnt=0;        for (int i=0;i<n-1;i++){            for (int j=i+1;j<n;j++){                int w=judge(a[i],a[j]);                if (w!=-1){//判断能否加边                     edge[cnt++]=(node){i,j,w};                }            }        }        sort(edge,edge+cnt);//排序         int sum=0;        int ans=0;        for (int i=0;i<cnt;i++){            int fu=find(edge[i].u);            int fv=find(edge[i].v);            if (fu!=fv){                sum++;                ans+=edge[i].w;                fa[fu]=fv;            }            if (sum==n-1)break;        }        if (sum!=n-1)printf ("-1\n");        else printf ("%d\n",ans);    }    return 0;}
阅读全文
0 0
原创粉丝点击