3.25

今日
7-7 总是学不会
分数 25
作者 yihan
单位 成都信息工程大学
题目描述
异或好啊,异或得学。
因为 yihan 总是学不会,所以决定让大伙一起体验一下这种感觉。但是由于 yihan 比较善良,于是决定不折磨大伙了。(出完发现有原题,但是不管了,相信大伙。)
题目给了一个 n,表示有 n 个点,每个点有一个属于自己的价值。
两个点之间可以花费两点的异或值的代价连一条边,例如(a和b,两个点可以花费a^b的代价在两点之间连一条边)。
请问将 n 个点连到一起要的最小代价和最大代价?(只能有n-1条边)

输入格式:
输入共 2 行。
第一行,一个整数 n (0≤n≤4000),表示总共有 n 个点。
第二行,n 个整数,代表每个点的价值 ai (1≤i≤n,1≤ ai ≤1000000000),中间以空格隔开。

输出格式:
输出最小价值和最大价值,中间以空格隔开。

输入样例:
在这里给出一组输入。例如:

3
1 2 3
输出样例:
在这里给出相应的输出。例如:

3 5
代码长度限制
16 KB
时间限制
2000 ms
内存限制
256 MB
栈限制
8192 KB
krusikal算法实现

include<bits/stdc++.h>

using namespace std;

define int long long

const int N=4010;
int val[N];
int fa[N];
void init()
{
for(int i=0;i<N;i++)
{
fa[i]=i;
}
}
int findx(int x)
{
return fa[x]x?x:fa[x]=findx(fa[x]);
}
struct edge{
int x,y;
int val;
};
bool cmp1(edge & a,edge & b)
{
return a.val<b.val;
}
bool cmp2(edge & a,edge & b)
{
return a.val>b.val;
}
signed main()
{ ios::sync_with_stdio(0);
cin.tie(0);
init();
int n;
cin>>n;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
val[i]=x;
}
vectorbian;
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
bian.push_back({i,j,val[i]^val[j]});
}
}
int maxv=0,minv=0;
sort(bian.begin(),bian.end(),cmp1);
int cnt=0;
for(int i=0;i<bian.size();i++)
{
int x=findx(bian[i].x);
int y=findx(bian[i].y);
if(x!=y)
{
fa[y]=x;
cnt++;
minv+=bian[i].val;
}
if(cnt
n-1)break;
}
init();
sort(bian.begin(),bian.end(),cmp2);
cnt=0;
for(int i=0;i<bian.size();i++)
{
int x=findx(bian[i].x);
int y=findx(bian[i].y);
if(x!=y)
{
fa[y]=x;
cnt++;
maxv+=bian[i].val;
}
if(cnt==n-1)break;
}
cout<<minv<<" "<<maxv;
return 0;
}
//原理:遍历所有边,同时应用并查集,构建最小生成树,得到最小最大代价

include<bits/stdc++.h>

using namespace std;

define int long long

const int INF=0x3f3f3f3f3f3f3f3f,N=4010;
int n;
int val[N];
int min_val(){
int dist[N];
bool vis[N];
memset(dist,0x3f,sizeof dist);
memset(vis,0,sizeof vis);

dist[0]=0;
int sum=0;
for(int i=0;i<n;i++)
{
int u=-1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&(u-1||dist[j]<dist[u]))u=j;
}
vis[u]=1;
sum+=dist[u];
for(int v=0;v<n;v++)
{ if(v
u)continue;
if(!vis[v])
{
int w=val[u]^val[v];
if(dist[v]>w)
{
dist[v]=w;
}
}
}
}
return sum;
}
int max_val(){
vector dist(n,-INF);
vector vis(n,0);
dist[0]=0;
int sum=0;
for(int i=0;i<n;i++)
{
int u=-1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&(u-1||dist[j]>dist[u]))u=j;
}
vis[u]=1;
sum+=dist[u];
for(int v=0;v<n;v++)
{
if(v
u)continue;
if(!vis[v])
{
int w=val[u]^val[v];
if(dist[v]<w)
{
dist[v]=w;
}
}
}
}
return sum;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
val[i]=x;
}
int min_va=min_val();
int max_va=max_val();
cout<<min_va<<" "<<max_va;
}
//prim算法:每次找到距已知点集最近/远的点加入集合并更新未达点集,类似djkstra算法?但是区别:1.循环次数dj为n-1,prim为n原因是第一次是将起点加入sum,n次找到n个点最近/远距离 2,更新方式不同

posted @ 2026-03-25 17:04  douzishuo  阅读(11)  评论(0)    收藏  举报