这道题坑了我好几个小时,首先算循环节小于k的全满的状态,在一个节点然后一条边的加上去。例如,K = 5,当K=4的时候是全满的状态,此时只需要添加一个节点和边,使其再产生一个环。通过规律可以知道,因为添加一个节点以前是全满的状态,所以对于一个新增加的节点,第一次添加两条边,干掉一个环,以后每增加一条边,会干掉2、3、4……用计数器记录一下就好。
如果全填满了还不满足,在增加一个节点如此进行,必定可以保证最优解。
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#include <stack>
#include <cmath>
#include <string>
#include <vector>
#include <cstdlib>
//#include <bits/stdc++.h>
//#define LOACL
#define space " "
using namespace std;
typedef long long LL;
typedef __int64 Int;
typedef pair<int, int> paii;
const int INF = 0x3f3f3f3f;
const double ESP = 1e-5;
const double PI = acos(-1.0);
const int MOD = 1e9 + 7;
const int MAXN = 100 + 10;
int ans[104][104];
int main() {
int K, temp, t;
while (scanf("%d", &K) != EOF) {
memset(ans, 0, sizeof(ans));
for (int i = 3; i <= 100; i++) {
if (i*(i - 1)*(i - 2)/6 >= K) {
t = i;
temp = i*(i - 1)*(i - 2)/6;
break;
}
}
if (temp == K) {
for (int i = 0; i < t; i++) {
for (int j = 0; j < t; j++) {
ans[i][j] = !(i == j);
}
}
}
else {
K -= (t - 1)*(t - 2)*(t - 3)/6;
for (int i = 0; i < t - 1; i++) {
for (int j = 0; j < t - 1; j++) {
ans[i][j] = !(i == j);
}
}
for (; t <= 100; t++) {
int cnt = 1;
while (K >= cnt) {
if (cnt == 1) {
ans[t - 1][0] = ans[t - 1][1] = 1;
ans[0][t - 1] = ans[1][t - 1] = 1;
}
else {
for (int i = 0; i < t; i++) {
bool flag = false;
for (int j = 0; j < t; j++) {
if (!ans[i][j] && i != j) {
ans[i][j] = ans[j][i] = 1;
flag = true; break;
}
}
if (flag) break;
}
}
K -= cnt; cnt++;
}
if (K == 0) break;
}
}
printf("%d\n", t);
for (int i = 0; i < t; i++) {
for (int j = 0; j < t; j++) {
printf("%d", ans[i][j]);
}
printf("\n");
}
}
return 0;
}