P10643 题解
Aventurine_stone · · 题解
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;
}