1 条题解
-
0
自动搬运
来自洛谷,原作者为

Aventurine_stone
(已AFO)愿人生的赌局,赢的总是我们。搬运于
2025-08-24 22:59:53,当前版本为作者最后更新于2024-07-29 16:08:07,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
1. 题目分析
先看数据范围,。如此小的数据范围,首先考虑是否可以使用模拟退火。
模拟退火可以跑十万次,但我们很快可以发现,此题对于一个随机的序列,我们很难找到一个参数用来判断此序列的优劣,故不能用模拟退火解题。
既然不是模拟退火,那么此题很明显便是一道构造题。2. 题目做法
我们可以将他们的朋友关系做成一张图。然后创建一个数组记录每个人使用的乐器,这里我用 表示萨克斯,用 表示钢琴。然后用一个数组记录每个人的朋友个数,再用一个数组记录每个人与他使用不同乐器的朋友个数。
对于乐器记录数组,我们可以先随机生成一个序列,然后算出初始的不同乐器数组,之后我们对于一个人,如果他的拥有不同乐器的朋友数不符合题意,那么我们让他主修另外一种乐器,让他符合题意。就这样一直操作,直到得到一个符合题意的方案,然后输出。
每次操作的时间复杂度为 ,那么最坏情况下我们要进行多少次操作呢?猜测:
最多进行 次操作。
证明:
初始时,对于一对朋友关系,如果他们使用的是不同的乐器,我们可以将此关系看作不同色关系,反之则为同色关系。
可以看出,我们每进行一次操作,那么同色关系将至少减少一,最多只有 个同色关系,故最多进行 次操作。
证毕。
故时间复杂度为 ,可以轻松通过此题。3. 代码
#include<bits/stdc++.h> using namespace std; const int N=210,M=40010;//记得开够空间 inline int read() { int x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar(); return x; } int head[N],ne[M],e[M],idx; inline void add(int x,int y)//建边 { ne[++idx]=head[x]; head[x]=idx; e[idx]=y; } int n,m; bool p[N]; int num[N],cnt[N]; inline void change(int x)//修改乐器 { cnt[x]=num[x]-cnt[x]; for(int i=head[x];i;i=ne[i]) { int c=e[i]; if(p[x]^p[c]) cnt[c]++; else cnt[c]--; } } int x,y; bool pd; int main() { n=read(),m=read(); while(m--) { x=read(),y=read(); add(x,y),add(y,x); num[x]++,num[y]++; } for(int i=1;i<=n;i++) p[i]=rand()&1; for(int i=1;i<=n;i++) { for(int j=head[i];j;j=ne[j]) { int c=e[j]; if(p[i]^p[c]) cnt[i]++; } } pd=1; for(int i=1;i<=n;i++) { if((cnt[i]<<1)<num[i]) { x=i,pd=0; break; } } while(!pd)//进行操作 { p[x]=!p[x]; change(x); pd=1; for(int i=1;i<=n;i++) { if((cnt[i]<<1)<num[i]) { x=i,pd=0; break; } } } for(int i=1;i<=n;i++) { if(p[i]) printf("P"); else printf("S"); } return 0; }
- 1
信息
- ID
- 10416
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者