[网络流24题]魔术球问题——最小路径覆盖 大佬们的博客 Some Links

题目大意:

假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,…的球。
(1)每次只能在某根柱子的最上面放球。
(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。
试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可放11 个球。
对于给定的n,计算在n根柱子上最多能放多少个球。

思路:

其实我一开始的思路是这样的:把可以放在一起的球之间连一条流量为1的边,然后每个球拆成两个点,中连一条流量为1 的费用为-1的边,然后其实我们要求的就是在流量限制为n下的最小费用。然后发现这种方法太不正常了。
其实正解是转化为了图论的模型的,先假设每个球单独放在一根柱子上面,然后再来合并球,求最大的合并次数。两个球之间连有向边了之后,就是一个最小路径覆盖的模型了。然后就转化为二分图跑最大流就好了。
至于输出方案的话,就把流满的边找出来乱搞一下就好了。

/*========================
 * Author : ylsoi
 * Problem : luogu2765
 * Algorithm : Max_Flow
 * Time : 2018.7.13
 * ========================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("luogu2765.in","r",stdin);
    freopen("luogu2765.out","w",stdout);
}

const int maxn=55+10;
const int maxm=5e4+10;
const int inf=INT_MAX;
int n,ss,tt,tot,ans;
int beg[maxm],las[maxm<<1],to[maxm<<1],flow[maxm<<1],cnte=1;

void add(int u,int v,int f){
    las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; flow[cnte]=f;
    las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; flow[cnte]=0;
}

struct dinic{
    int cur[maxm],num[maxm],Max_flow;
    queue<int>qu;
    bool bfs(){
        memset(num,0,sizeof(num));
        qu.push(ss); num[ss]=1;
        while(qu.size()){
            int u=qu.front(); qu.pop();
            for(int i=beg[u];i;i=las[i]){
                if(!flow[i] || num[to[i]])continue;
                num[to[i]]=num[u]+1;
                qu.push(to[i]);
            }
        }
        return num[tt];
    }
    int dfs(int u,int gap){
        if(u==tt || !gap)return gap;
        int sum=0,f;
        for(int &i=cur[u];i;i=las[i]){
            if(num[to[i]]!=num[u]+1)continue;
            if((f=dfs(to[i],min(flow[i],gap)))){
                gap-=f;
                sum+=f;
                flow[i]-=f;
                flow[i^1]+=f;
            }
            if(!gap)break;
        }
        return sum;
    }
    bool cal(){
        while(bfs()){
            REP(i,ss,tot)cur[i]=beg[i];
            Max_flow+=dfs(ss,inf);
        }
        return ans-Max_flow<=n;
    }
}T;

int fa[maxm];
int find(int x){return fa[x]==x ? x : fa[x]=find(fa[x]);}

void work(){
    ss=1; tt=2; tot=2;
    while(T.cal()){
        ++ans;
        add(ss,tot+1,1);
        add(tot+2,tt,1);
        for(int i=1;i*i<2*ans;++i)
            if(i*i-ans>0)
                add(tot+1,(i*i-ans+1)*2,1);
        tot+=2;
    }
    ans=ans-1;
    printf("%d\n",ans);
    REP(i,1,ans)fa[i]=i;
    REP(i,1,ans)
        for(int j=beg[i*2+1];j;j=las[j])
            if(to[j]%2==0 && to[j]>=4 && !flow[j])
                fa[find(i)]=find(to[j]/2-1);
    set<int>s[maxm];
    REP(i,1,ans)s[find(i)].insert(i);
    set<int>::iterator it;
    REP(i,1,ans)if(s[i].size()){
        for(it=s[i].begin();it!=s[i].end();++it)
            printf("%d ",*it);
        putchar('\n');
    }
}

int main(){
    File();
    scanf("%d",&n);
    work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/81028020
今日推荐