Power OJ 魔术球问题

来源:互联网 发布:苹果音频编辑软件 编辑:程序博客网 时间:2024/06/05 20:50

嗯,如果i+j为平方数的话,就代表可以连边(i,j)。然后放在柱子上,最多能放多少球,就是在有限的柱子内放更多的球,反过来想,对于确定的球来说,用最少的柱子其实就是求一个最小路径覆盖。那么我们去枚举答案球的个数,然后找到最小路径覆盖数刚好大于给定的n的时候,那么答案就是当时的球数-1。建图不要每次枚举答案的时候重建,会超时。我们不难发现,当球的个数加1的时候增加的边其实不多。

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int MAXN = 1600;const int inf = 1e9;int n,m;bool is_square(int x){    int m = sqrt(x);    return m*m == x;}bool vis[MAXN];int match[MAXN];vector<int>head[MAXN];bool dfs(int u){    for(auto v : head[u])    {        if(!vis[v])        {            vis[v] = 1;            if(match[v] == -1 || dfs(match[v]))            {                match[v] = u;                return 1;            }        }    }    return 0;}int check(int n){    for(int i = 1; i < n; ++i)if(is_square(i+n))head[i].push_back(n);    for(int i = 1; i <= n; ++i)match[i] = -1;    int ans = 0;    for(int i = 1; i <= n; ++i)    {        fill(vis+1,vis+1+n,0);        if(dfs(i))ans++;    }    return n - ans;}int main(){    scanf("%d",&n);    for(int i = 1; i <= n; ++i)        for(int j = i+1; j <= n; ++j)        {            if(is_square(i+j))head[i].push_back(j);        }    int ans = n+1;    while(check(ans) <= n)ans++;    ans--;    check(ans);    printf("%d\n",ans);    stack<int>q;    for(int i = ans; i >= 1; --i)    {        if(match[i] >= 1)        {            int v = i,u;            while(match[v] >= 1)            {                q.push(v);                u = match[v];                match[v] = 0;                v = u;            }            printf("%d",v);            match[v] = 0;            while(!q.empty())printf(" %d",q.top()),q.pop();            puts("");        }        else if(match[i] == -1)printf("%d\n",i);    }    return 0;}
原创粉丝点击