原题请看这里
ZYB喜欢阅读侦探小说和侦探漫画。 有一天,他沉迷于这样的故事:
作为B国的间谍,您已经潜伏在A国多年了。 在国家A中有n个部队和m个军团,每个部队仅属于一个军团。 您的任务是调查每个部队属于哪个军团。
一天,你截获了一份记录军队之间关系的情报,从情报中,对于每一对(i,j),可以得到军队i和军队j是否属于同一个军团。然而,每条数据有1/s的独立概率是错误的。
准确的说,军队编号从0到n-1,军团编号从0到m-1。你会给定n(n-1)/2个Boolean型数,表示军队i和军队j是否属于同一军团(1表示是,0表示不是)。每条Boolean型数据有1/S的概率是错误的。你可以认为数据通过以下代码生成:
其中,b[i]表示军队i属于的军团编号。rand()是一个随机生成[0,lcm(m,S)-1]范围内的数的随机函数(玄学)。
现在你知道n和S,但是不知道m的值,请帮B国还原原始数据。
输入包含多组数据。
输入的第一行包含一个整数T (1≤T≤100)表示数据组数
对于每组数据,输入的第一行包含两个整数n,S(30≤n≤300,20≤S≤100)表示部队人数和用于生成数据的整数参数。 在下一行中有一个二进制字符串(即该字符串仅包含“ 0”和“ 1”),其长度为n(n-1)/2,描述成对关系。
它的排列如下:(0,1),(0,2)…(0,n−1),(1,2)…(n−3,n−1),(n−2,n−1).
m没有给出,但是可以保证1≤m≤⌊n/30⌋.所有的T组数据中的n的值不超过1200
对于每种情况,输出整数用空格分隔,第i个整数描述 b e i be_i bei。请以最小的词典顺序输出解决方案。 例如,如果有4个部队和2个地区{0,3},{1,2},你应该输出0 1 1 0.
1
10 20
101110101010101010100010010101010100101010010
0 0 1 0 1 0 1 0 1 0
打比赛的时候看都没看…
首先,在所给数据中找出 a 1 a_1 a1, a 2 a_2 a2, a 3 a_3 a3… a n a_n an与a在同一个集合内,然后枚举b,如果b与a在同一集合,但是b与 a 1 a_1 a1, a 2 a_2 a2, a 3 a_3 a3… a n a_n an不在同一集合,那么显然是错误的。题目中说了有1/S的概率这个数据是错误的(雾),所以需要调参。
所以本题可以通过以下方法做:
for(枚举a)
{
......
for(int i=1;i<=n;i++)
{
......
for(枚举b)
{
......
}
......
}
......
//调参
}
看起来这个代码时间复杂度是O(n^3)!!!但其实循环是跑不满的,第一个循环跑集合个数,第三个循环跑集合元素,所以实际时间复杂度为O(n ^2)
#include
using namespace std;
const int MAXN=2e3+5;
int f[MAXN][MAXN],a[MAXN],n,s,T,id,len,num;
vector<int> v;
char ch;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&s);
memset(a,-1,sizeof(a));
memset(f,0,sizeof(f));
id=0;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
scanf(" %c",&ch);
f[i][j]=f[j][i]=ch-'0';
}
f[i][i]=1;
}
for(int i=1;i<=n;i++)
if(a[i]==-1)
{
v.clear();
for(int j=1;j<=n;j++)
if(f[i][j]&&a[j]==-1) v.push_back(j);
len=v.size();
for(int j=1;j<=n;j++)
{
num=0;
for(int k=0;k<v.size();k++)
if(f[v[k]][j]&&a[j]==-1) num++;
if(num*2>=len) a[j]=id;//调参
}
id++;
}
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
printf("\n");
}
}
这代码写的我一愣一愣的,WA了好几发