题目描述
假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2,3,4⋯ 的球。
每次只能在某根柱子的最上面放球。
在同一根柱子中,任何 2 个相邻球的编号之和为完全平方数。
试设计一个算法,计算出在 n 根柱子上最多能放多少个球。
输入格式
文件第 1 行有 1 个正整数 n,表示柱子数。
输出格式
第一行是球数。接下来的 n 行,每行是一根柱子上的球的编号。
样例
样例输入
4
样例输出
11
1 8
2 7 9
3 6 10
4 5 11
数据范围与提示
1≤n≤55
模型很好建立。
如果
i+j
i
+
j
能构成一个完全平方数就连一条
(i+j)
(
i
+
j
)
的有向边
然后就变成了最小路径覆盖
不知道上界?
没关系,我们从小到大依次加入点,跑一边最小路径覆盖
如果大于
n
n
了,我们就并输出答案
我写的是匈牙利
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int ans;
int k , n;
int linkk[11000] , t , match[11000];
int a[11000];
bool vis[11000];
struct node{
int n , y , v;
}e[1001000];
int read()
{
int sum = 0;char c = getchar();bool flag = true;
while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
if(flag) return sum;
else return -sum;
}
void insert(int x,int y,int z)
{
e[++t].y = y;e[t].n = linkk[x];e[t].v = z;linkk[x] = t;
return;
}
bool dfs(int x)
{
for(int i = linkk[x];i;i = e[i].n)
if(!vis[e[i].y])
{
int y = e[i].y;
vis[y] = true;
if(!match[y] || dfs(match[y]))
{
match[y] = x;
match[x] = y;
return true;
}
}
return false;
}
void work()
{
for(int i = 1;i <= 200;++i) a[i] = i * i;
int now = 1;
while(1)
{
n++;
while(a[now] <= n) now++;
for(int i = now;a[i] > n && 2 * n > a[i];++i)
insert(2 * (a[i] - n) - 1,2 * n,1);
for(int i = 1;i <= 2*n;++i)
{
memset(vis,0,sizeof(vis));
if(!match[i])
if(dfs(i))
{
ans++;
}
}
if(n - ans > k)
{
printf("%d\n",n-1);
memset(vis,0,sizeof(vis));
for(int i = 1;i < n;++i)
if(!vis[2*i-1])
{
int x = 2 * i;
while(1)
{
x--;
vis[x] = true;
printf("%d ",(x + 1)/2);;
if(match[x] == 0) break;
x = match[x];
}
printf("\n");
}
return;
}
}
return;
}
int main()
{
k = read();
work();
return 0;
}