2020 年 “联想杯”全国高校程序设计在线邀请赛暨第三届上海理工大学程序设计竞赛 D. Disaster Recovery(最小生成树)

题目

题目大意:一共有n个点,m条边,一个点到另一个点的距离等于这两个点斐波那契数之和,现要求联通这n个点,并且在路径最短的情况下输出度数最大的点的度数。

思路:当时比赛的时候想到了最小生成树,但是这个路径长度不会处理,数学是真的差,就一个斐波那契数列的性质都没想到,补的时候还以为要数据离散化,然而只要排个序,然后最小生成树就行了。

#include
using namespace std;
#define pi acos(-1)
#define mod 998244353
#define INF 0x3f3f3f
#define fi first
#define se second
#define it iterator
#define ins insert
#define mp make_pair
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define ll long long
#define ull unsigned long long
#define mem(a) memset(a,0,sizeof(a))
#define cio ios::sync_with_stdio(false)
#define gcd __gcd
ll lgcd(ll a,ll b){return b == 0? a:lgcd(b, a % b);}
int lowbit(int x){return x&(-x);}
#define T int t;scanf("%d",&t);while(t--)
#define CE cout << endl
#define C(n) cout << n << endl
#define CY cout << "YES" << endl
#define CN cout << "NO" << endl
#define Cy cout << "Yes" << endl
#define Cn cout << "No" << endl

struct node
{
	int x, y, z;
}s[200010];
int d[100010];
int q[100010];

// 排序是关键:斐波那契数列,两组数中大下标大的那组肯定大,如果一样比较小下标即可
bool cmp(node a, node b)
{
	if(a.y!=b.y) return a.y < b.y;
	return a.x < b.x;
}

// 并查集
int ffind(int x)
{
    if(q[x]!=x){
        return q[x]=ffind(q[x]);
    }else{
        return q[x];
    }
}
void com(int x, int y)
{
    int xx = ffind(x);
    int yy = ffind(y);
    q[yy] = xx;
}

int main()
{
	int n, m;
	cin >> n >> m;
	for(int i = 0; i <= n; i++) q[i] = i;
	for(int i = 0; i < m; i++){
		cin >> s[i].x >> s[i].y;
		// 无向图,x为小下标,y为大下标,便于比较
		if(s[i].x>s[i].y) swap(s[i].x,s[i].y);  
	}
	sort(s,s+m,cmp);  // 按照权值排序
	int k = 1;  // 统计已生成的边数
	for(int i = 0; i < m; i++){
		if(k==n) break;  // 边数等于点数生成树已完成
		int v1 = s[i].x;
		int v2 = s[i].y;
		if(ffind(v1)!=ffind(v2)){  // 两个点未在同一个集合内,生成一条边
			com(v1,v2); // 归并两个点
			d[v1]++;  // 统计度数
			d[v2]++;  // 统计度数
			k++;  // 更新边数
		}
	}
	// 取度数最大值
	int maxn = d[1];
	for(int i = 2; i <= n; i++) maxn = max(maxn,d[i]);
	C(maxn);
	return 0;
}

你可能感兴趣的:(题解)