题目地址:点击打开链接
题意:n个点,m条边,无向图,边有两种,一种价值为1,一种价值为0,问你组成的生成树的价值是否可能是一个素数。
思路:对边按价值进行排序,然后按价值从小到大和从打大到小分别求一次生成树,得到一个maxval和minval,只要看下minval到
maxval之间有没有素数就可以了。
因为这个范围内的值都可以换边进行得到。最小生成树一定是你含1最少的生成树,因此类似与次小生成树,每次找一个不在最小生
成树上的长度为1的边添加进去,则一定会形成一个环,去掉这个环上的一条长度是0的边则一定会形成一个更大的生成树,不断执
行当前操作,直到生成树的值不变,也就是变成了1最多的生成树,也就是最大生成树
注意有可能不存在生成树。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e5+5;
int n, m, pre[maxn];
bool prime[maxn] = {1, 1, 0};
struct node
{
int u, v, w;
node() {}
node(int uu, int vv, int ww): u(uu), v(vv), w(ww) {}
bool operator <(const node &a) const
{
return w < a.w;
}
}a[maxn];
void init()
{
for(int i = 2; i < maxn; i++)
if(!prime[i])
for(int j = 2; i*j < maxn; j++)
prime[i*j] = 1;
}
int Find(int x)
{
int r = x;
while(pre[r] != r) r = pre[r];
int i = x, j;
while(i != r)
{
j = pre[i];
pre[i] = r;
i = j;
}
return r;
}
bool join(int x, int y)
{
int a = Find(x);
int b = Find(y);
if(a != b)
{
pre[b] = a;
return 1;
}
return 0;
}
int main(void)
{
int t, ca = 1;
init();
cin >> t;
while(t--)
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
a[i] = node(u, v, w);
}
sort(a+1, a+1+m);
for(int i = 1; i <= n; i++)
pre[i] = i;
int cnt1 = 0, cnt2 = 0, cnt = 0;
for(int i = 1; i <= m; i++)
{
if(join(a[i].u, a[i].v))
cnt1 += a[i].w, cnt++;
if(cnt == n-1) break;
}
cnt = 0;
for(int i = 1; i <= n; i++)
pre[i] = i;
for(int i = m; i >= 1; i--)
{
if(join(a[i].u, a[i].v))
cnt2 += a[i].w, cnt++;
if(cnt == n-1) break;
}
bool ok = 0;
for(int i = cnt1; i <= cnt2; i++)
if(!prime[i])
{
ok = 1;
break;
}
printf("Case #%d: ", ca++);
if(!ok || cnt != n-1) puts("No");
else puts("Yes");
}
return 0;
}