这道题坑了我好几个小时,首先算循环节小于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 ", t); for (int i = 0; i < t; i++) { for (int j = 0; j < t; j++) { printf("%d", ans[i][j]); } printf(" "); } } return 0; }