#6003. 「网络流 24 题」魔术球
内存限制:256 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:Special Judge
上传者: 匿名
题目描述
输入格式
输出格式
样例
数据范围与提示
把每个柱子当成一条路径,能构成完全平方数的两个数当成连通的两个点 最大流||二分匹配的模型就构建好了
一开始从从小到大建图 每次都要初始化 T了 学了一下大神的优化建图 。。。就是从大向小建图 这样每次就不用初始化了 因为二分匹配的实质 就是 更改以前的匹配当不会
更改最优的情况时 才更改匹配 所以如果不是最优则不会更改匹配 所以以前的最优匹配也不会因后加入的节点而更改
那么枚举球的数量即可 当独立子集数大于n时break;
(注:这题也可以贪心解,即每一个球都从前往后扫 能放就放)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL ;
const int inf = 500;
const int N = 4000;
const double eps = 1e-7;
struct node
{
int to, next;
} p[1000000];
int head[N], cnt;
int match[N], w[N];
bool vis[N];
void init()
{
memset(head,-1,sizeof(head));
memset(match,-1,sizeof(match));
memset(w,0,sizeof(w));
cnt=0;
return ;
}
void add(int u,int v)
{
p[cnt].to=v,p[cnt].next=head[u];
head[u]=cnt++;
return ;
}
int dfs(int u)
{
for(int i=head[u]; i!=-1; i=p[i].next)
{
int v=p[i].to;
if(vis[v]) continue;
vis[v]=1;
if(match[v]==-1||dfs(match[v]))
{
match[v]=u,w[u]=v;
return 1;
}
}
return 0;
}
int ans[N];
int num,o=2000, k;
void solve()
{
num++;
for(int i=1; i<num; i++) if(sqrt(i+num)==(int)sqrt(i+num)) add(num,i+o);
memset(vis,0,sizeof(vis));
k+=dfs(num);
return ;
}
int main()
{
init();
int n;
scanf("%d", &n);
num=0,k=0;
while(1)
{
solve();
if(num-k>n) break;
}
num--;
printf("%d\n",num);
k=0;
for(int i=1; i<=num; i++) if(!w[i]) ans[++k]=i;
for(int i=1; i<=k; i++)
{
printf("%d",ans[i]);
int x=o+ans[i];
while(match[x]!=-1)
{
printf(" %d",match[x]);
x=o+match[x];
}
puts("");
}
return 0;
}