题目描述
输入描述:
输出描述:
示例1
输入
1
10 20
101110101010101010100010010101010100101010010
输出
0 0 1 0 1 0 1 0 1 0
备注:
题目大意
给定
,
。然后有
个点,
个集合,对于点
,
,有
表示
和
是否在同一集合里,求每个点在第几个集合中。
但是,题目中的的数据有
的概率是错的!?(傻了)
分析
这题比赛时根本没去看,完了之后老师讲了再做的。
首先对于 ,在题目给出的数据中找出 , , …… 与 在同一集合,然后枚举 ,如果 和 在同一集合,然而 和其他与 同一集合的点若不在同一集合,那么显然是不对的。但是题目里说了,有 的概率是错的,所以可以判下。这里就有点调参的性质,后文中采用 。
因此我们只要
for(枚举a)
for(找到与a在同一集合的)
for(枚举b)
看起来是个O(n3)的算法,但是其实没有跑满的,
可以想见,第一层的for是跑集合个数,第三层是跑集合元素。合起来是O(n),
因此总的复杂度其实只有O(n2)。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=310;
int f[MAXN][MAXN],a[MAXN];
char ff[MAXN*MAXN];
vector<int> vec;
int main()
{
int t,n,s;
for(scanf("%d",&t);t--;){
scanf("%d%d%s",&n,&s,ff);
int cnt=0,num=0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
f[i][j]=f[j][i]=ff[cnt++]-'0';
}
f[i][i]=1;
}cnt=0;
fill(a,a+1+n,-1);
for(int i=0;i<n;i++){//枚举a
vec.clear();
if(a[i]!=-1) continue;
for(int j=0;j<n;j++)//找和a是同个集合的元素
if(f[i][j]&&a[j]==-1)
vec.push_back(j);
for(int j=0;j<n;j++)//枚举b
if(a[j]==-1){
num=0;
for(int k=0;k<vec.size();k++)
if(f[vec[k]][j]) num++;
if(num>=vec.size()/2) a[j]=cnt;//如果大于1/2,就合法。
}
cnt++;
}
for(int i=0;i<n;i++) printf("%d ",a[i]);
printf("\n");
}
}
END
玄学题目。搞到去世。