2018 ICPC亚洲区域赛徐州站 A题 Rikka with Minimum Spanning(Kruscal)

题意

给你一个图,问有多少个最小生成树,要求输出最小生成树个数乘以最小生成树的权值。

思路

数据是那样生成的,有相同的权值的边的概率特别小,可以视作不会发生(测试用例中也的确没有这样的数据)。题目中的代码 + 套Kruscal算法的代码就能过。

实际在做,考虑了重边的问题,u,v两个点如果有多条直连边,在Kruscal算法要取u,v的连线时,取其中最小的那个,并算出u,v之间一共有多少个权值与最小的那个相同的,记为num1。同理其他的两个点,记为num2、num3……
最后算出最小生成树的权值ans后,ans再乘以 ( n u m 1 ∗ n u m 2 ∗ … … ∗ n u m x ) (num1*num2*……*num_x) num1num2numx,记得取模。

但是这样做,如果题目给出的数据中,含有环,并且环上的最大值有多个,那么还是能hack掉这份代码的。

不过数据出的不好,一下子就过了。

实际要确保无误的做,还是得按题目提到的方法来做。
如下链接:https://blog.csdn.net/qq_40679299/article/details/88196872

代码

#include <bits/stdc++.h>
using namespace std;
const unsigned long long mod = 1e9 + 7;
const int maxn = 1e5 + 5;
unsigned long long k1, k2;
unsigned long long xorShift128Plus()
{
    unsigned long long k3 = k1, k4 = k2;
    k1 = k4;
    k3 ^= k3 << 23;
    k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
    return k2 + k4;
}
int n, m;
struct edge{
    int u, v;
    unsigned long long w;
}a[maxn];
bool cmp(edge e1, edge e2)
{
    if(e1.w == e2.w){
        if(e1.u == e2.u)
        {
            return e1.v < e2.v;
        }
        return e1.u < e2.u;
    }
	return e1.w < e2.w;
}
int fa[maxn];
void init_union_find(int n)
{
	for(int i = 1; i <= n; i++)
        fa[i] = i;
	return ;
}
int find_fa(int x)
{
	if(x == fa[x]){
        return x;
	}else{
        return fa[x] = find_fa(fa[x]);
    }
}
void unite(int u, int v)
{
    u = find_fa(u);
    v = find_fa(v);
	fa[v] = u;
	return;
}
bool same(int u, int v)
{
	u = find_fa(u);
    v = find_fa(v);
	if(u == v)
        return true;
	return false;
}
unsigned long long Kruskal()
{
	sort(a + 1, a + m + 1, cmp);
	init_union_find(n);
	unsigned long long res = 0;
	unsigned long long ans = 1;
	int cntcnt = 0;
	for(int i = 1; i <= m; i++)
    {
		edge e = a[i];
		
		if(!same(e.u, e.v))
		{
		    unite(e.u, e.v);
			res = (res + e.w) % mod;
            cnt++;
		}
	}
	if(cntcnt != n - 1)
        return 0;
	return (res * ans) % mod;
}
void gen()
{
    scanf("%d%d%llu%llu", &n, &m, &k1, &k2);
    for(int i = 1; i <= m; ++i)
    {
        a[i].u = xorShift128Plus() % n + 1;
        a[i].v = xorShift128Plus() % n + 1;
        a[i].w = xorShift128Plus();
        if(a[i].u > a[i].v)
            swap(a[i].u, a[i].v);
    }
}
int main(){
    int t;
    scanf("%d", &t);
    while(t--)
    {
        gen();
        cout << Kruskal() << endl;
    }
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值