LOJ6003 魔术球(网络流24题)

题目描述
假设有 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 ) 的有向边
然后就变成了最小路径覆盖
不知道上界?
没关系,我们从小到大依次加入点,跑一边最小路径覆盖
如果大于 n 了,我们就 b r e a k 并输出答案
我写的是匈牙利

#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;
} 

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/81319765