中文题干
这道题有点东西。。。
题目意思就不说了;
脑洞:首先要有一个判断完全平方数的函数,这个怎么判断也不说了。
这是网络流24题中的题,是要我们用网络流的知识来写吧。但是想用匈牙利来试试。。
这题有点动态的匈牙利的味道,就是这个二分图是在不断的变大的,直到他的最大独立点到达一个题目要求的值时,就停下来。
之前一直不知道怎么让他变大,一直觉得是不是加一次就要重新跑一遍算法。。
但后来怕是看到了大佬们的博客,有了点想法:
就是我们完全可以,将所有的数与他小的并且和是完全平方数的数相连一条边。
而每次加一个点的时候,我们就可以将这个点加进去,然后连边,最后只用对这个点进行匈牙利算法就可以了。。
然后想想,我们跑这个算法的时候,不就是一个点一个点的跑的吗。。。唉 太菜了。
至于如何输出序列,找我们的
l
l
l数组啊,里面早就给我们连好链了,等着我们输出呢。。。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define len 20005
using namespace std;
struct edge{
int u, v, nxt;
};
edge e[len];
int vis[len], l[len], vs[len];//vis数组和l数组都是匹配时候用的,vs数组在输出时候用
int head[len], hcnt;
void Init (){
//memset(vis, 0, sizeof (vis));
memset(l, 0, sizeof (l));
memset(head, -1, sizeof (head));
hcnt = 0;
}
void adde(int u, int v){
e[hcnt].u = u; e[hcnt].v = v;
e[hcnt].nxt = head[u]; head[u] = hcnt ++;
}
bool Find(int x){
//cout << "!!!" << x << endl;
for (int i=head[x]; ~i; i=e[i].nxt){
int v = e[i].v;
if (!vis[v]){
vis[v] ++;
if (!l[v] || Find(l[v])){
l[v] = x; return true;
}
}
}
return false;
}
bool check(int x, int y){
int tmp = sqrt(x + y);
if (tmp * tmp == (x + y))
return true;
else return false;
}
int main(){
int n;scanf("%d", &n);
Init();
int ans = 0, m = 0;
do {
m++;
for (int i=m-1; i>=1; i--) if (check(i, m)) adde(m, i);
memset(vis, 0, sizeof (vis));
if (Find(m)) ans ++;//把新的点加进去
}while(m - ans <= n);
//以下是输出
printf ("%d\n", m-1);
for (int i=1; i<=n; i++){
int ans = 1;
while (vs[ans]) ans ++;
while (l[ans]) {
printf ("%d ", ans);
vs[ans] ++;
ans = l[ans];
}
printf ("%d \n", ans);
ans = 1;
}
return 0;
}