• [网络流24题]魔术球问题


    Description

    假设有$n$根柱子,现要按下述规则在这$n$根柱子中依次放入编号为$1,2,3,...$的球。

    $1.$每次只能在某根柱子的最上面放球。

    $2.$在同一根柱子中,任何$2$个相邻球的编号之和为完全平方数。

    求在$n$根柱子上最多能放多少个球。

    Input

    第$1$行有$1$个正整数$n$,表示柱子数。

    Output

    第一行是球数。

    接下来的$n$行,每行是一根柱子上的球的编号。

    Sample Input

    4

    Sample Output

    11
    1 8
    2 7 9
    3 6 10
    4 5 11

    HINT

    $n;leq;100$

    Solution

    枚举答案$ans$,在图中建立节点$1,2,...,ans$。如果对于$i,j,;i<j$且$i+j$为一个完全平方数,建一条有向边$(i,j)$。该图是有向无环图,求最小路径覆盖。寻找最大的$ans$使得最小路径覆盖数$=n$。(枚举$ans$即可)

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 5005
    #define M 200001
    using namespace std;
    struct graph{
        int nxt,to,f;
    }e[M];
    int a[N<<1],g[N<<1],dep[N<<1],l,m,s,t,fl,ans,cnt=1;
    bool v[N];
    queue<int> q; 
    inline bool sq(int x){
        int k=sqrt(x);
        return k*k==x;
    }
    inline void addedge(int x,int y,int f){
        e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f;
    }
    inline void adde(int x,int y,int f){
        addedge(x,y,f);addedge(y,x,0);
    }
    inline bool bfs(int u){
        memset(dep,0,sizeof(dep));
        q.push(u);dep[u]=1;
        while(!q.empty()){
            u=q.front();q.pop();
            for(int i=g[u];i;i=e[i].nxt)
                if(e[i].f>0&&!dep[e[i].to]){
                    q.push(e[i].to);
                    dep[e[i].to]=dep[u]+1;
                }
        }
        return dep[t];
    }
    inline int dfs(int u,int f){
        int ret=0;
        if(u==t) return f;
        for(int i=g[u],d;i&&f;i=e[i].nxt)
            if(e[i].f>0&&dep[e[i].to]>dep[u]){
                d=dfs(e[i].to,min(e[i].f,f));
                e[i].f-=d;e[i^1].f+=d;f-=d;ret+=d;
            }
        return ret;
    }
    inline void dinic(){
        while(true){
            if(!bfs(s)) return;
            fl+=dfs(s,N);
        }
    }
    inline bool chk(int x){
        dinic();
        return x-fl<=m;
    }
    inline void find(int u){
        a[++l]=u;
        for(int i=g[u];i;i=e[i].nxt)
            if(e[i].to!=s&&!v[e[i].to-N]&&!e[i].f){
                v[e[i].to-N]=true;find(e[i].to-N);
            }
    }
    inline void Aireen(){
        scanf("%d",&m);ans=m;
        s=N-1;t=(N<<1)-1;
        for(int j=1;j<=ans;++j){
            adde(s,j,1);adde(j+N,t,1); 
            for(int i=1;i<j;++i)
                if(sq(i+j)) adde(i,j+N,1);
        }
        do{
            ++ans;
            adde(s,ans,1);adde(ans+N,t,1); 
            for(int i=1;i<ans;++i)
                if(sq(i+ans)) adde(i,ans+N,1);
        }while(chk(ans));
        printf("%d
    ",ans-1);
        v[ans]=0;
        for(int i=1;i<ans;++i)
            if(!v[i]){
                l=0;v[i]=true;find(i);
                for(int j=1;j<=l;++j)
                    printf("%d ",a[j]);
                printf("
    ");
            }
    }
    int main(){
        freopen("ball.in","r",stdin);
        freopen("ball.out","w",stdout);
        Aireen();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    excel 上标和下标
    Excel之tab键
    Excel分数、小数、身份证的录入
    excel快速访问工具栏和自定义选项卡
    excel如何快速实现数据区域的框选
    excel 如何快速实现绝对引用
    INT函数和ROUND
    Excel Vlookup 列查找函数
    excel合并同类项去重求和功能
    VBA 一个很神奇的东西
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6240801.html
Copyright © 2020-2023  润新知