zoukankan      html  css  js  c++  java
  • [网络流24题]魔术球问题

    链接

    题意:给定一些数,每个数可以叠在前面某一堆上面(需要满足与最上面那个成完全平方),也可以自成一列,堆数有限定,求最多的球数

    做法:

    网络最大流(二分图匹配)

    从上面的题意整理出这样的情况:

    1.一个球可以找到一个比它小的数匹配,则由这个数连向那个小的数

    2.也可能一枝独秀,建立一个新堆

    每加入一个数,通过1情况连接对应边,进行一次二分图匹配,看能不能匹配到某个点,如果可以,则表明可以放在某个数上面,暂时放在这上面;如果不能,则只能自成一派。当总堆数超过限制时停止加数字。

    实际上,总的数字可能比较多(1500左右),直接匈牙利算法可能过不了,可以用dinic

    Code:

    #include<bits/stdc++.h>
    #define N 50000
    #define INF 1000000000
    using namespace std;
    int n,s=0,t=(N<<1)-1,maxflow;
    int sum,used;
    int dep[N<<1],nxt[N<<1],fir[100];
    
    struct Edge
    {
    	int next,to,flow;
    }edge[N<<4];int head[N<<1],cnt=1;
    void add_edge(int from,int to,int flow)
    {
    	edge[++cnt].next=head[from];
    	edge[cnt].to=to;
    	edge[cnt].flow=flow;
    	head[from]=cnt;
    }
    void add(int from,int to,int flow)
    {
    	add_edge(from,to,flow);
    	add_edge(to,from,0);
    }
    
    int bfs()
    {
    	memset(dep,0,sizeof(dep));
    	queue<int> q; while(!q.empty()) q.pop();
    	q.push(s); dep[s]=1;
    	while(!q.empty())
    	{
    		int u=q.front(); q.pop();
    		for(int i=head[u];i;i=edge[i].next)
    		{
    			int v=edge[i].to;
    			if(!dep[v]&&edge[i].flow)
    			{
    				dep[v]=dep[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	return dep[t];
    }
    int dfs(int u,int limit)
    {
    	if(u==t||!limit) return limit;
    	int k,flow=0;
    	for(int i=head[u];i;i=edge[i].next)
    	{
    		int v=edge[i].to;
    		if(dep[v]==dep[u]+1&&(k=dfs(v,min(limit,edge[i].flow))))
    		{
    			if(v!=t) nxt[u>>1]=v>>1;
    			edge[i].flow-=k;
    			edge[i^1].flow+=k;
    			limit-=k;
    			flow+=k;
    		}
    	}
    	return flow;
    }
    int dinic()//普通的最大流 
    {
    	maxflow=0;int k;
    	while(bfs())
    	{
    		while((k=dfs(s,INF))) maxflow+=k;
    	}
    	return maxflow;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	while(used<=n)
    	{
    		sum++;add(s,sum<<1,1);add((sum<<1)|1,t,1);
            for(int i=sqrt(sum)+1;i*i<2*sum;++i)
            add((i*i-sum)<<1,(sum<<1)|1,1);
            int k=dinic();
    		//将前一个数的起点于sum的终点相连 
    		if(!k) fir[++used]=sum;
    		//不能由其他点做起点流到汇点,只能重新开柱子自己做起点 
    	}
    	printf("%d
    ",--sum);
    	for(int i=1;i<=n;++i)
    	{
    		for(int j=fir[i];j;j=nxt[j]) printf("%d ",j);
    		printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    git add . 的时候遇到warning: LF will be replaced by CRLF inXXX 解决办法
    用Merge存储引擎中间件实现MySQL分表
    隐型马尔科夫模型(HMM) 简介
    隐型马尔科夫模型(HMM)向前算法实例讲解(暴力求解+代码实现)---盒子模型
    数据输入——生成你需要的echart图(世界地图,气泡图)
    数据输入——生成你需要的echart图(堆积柱状图、扇形图、嵌套环形图)
    jython实现java运行python代码
    django第四课 标签的用法(if/else、for、ifequal、过滤器、注释等)
    django第三课 模版
    paddlepaddle使用(一)
  • 原文地址:https://www.cnblogs.com/Chtholly/p/10665945.html
Copyright © 2011-2022 走看看