zoukankan      html  css  js  c++  java
  • 「网络流24题」 4. 魔术球问题

    「网络流24题」 4. 魔术球问题

    <题目链接>


    最小路径覆盖。

    给定了柱子数n(最小路径覆盖数)以及放球条件(建边条件),求最多有多少个球(最多有多少个点可以满足这个最小路径覆盖数)。

    枚举球的数量。

    每来一个球(点)m,枚举1..m-1的每个点i,若i+m满足建边条件(和为完全平方数)则按以下方式建边——

    套路拆点,每个点i拆成Xi、Yi,对于一组i、m,连Xi<->Y(m+5000)双向,跑匈牙利算出最大匹配。

    根据二分图相关定理:最小路径覆盖数=点数-最大匹配数。

    算出当前图的最小路径覆盖k,与给定柱子数比较。

    • k<n,继续加球。
    • k=n,可能还有更大的答案,继续加球。
    • k>n,m-1就是答案,停止加球。

    输出路径,遍历1..m-1每个X部点,向其匹配点走,直到无路可走,沿路标记为已遍历。

    已遍历过的X部点不再遍历。

    解释下为什么需要双向边。

    如图(乱画的),来了一个m点后,紫色边是新加的边。

    为避免TLE,我们不是清空整个图的匹配信息重跑匈牙利,而是在原匹配的基础上以m为起点进行增广。

    这就需要我们从Y部的点开始——这就是建双向边的原因。

    不可以直接连Y部->X部,因为这会导致你无法沿匹配点输出路径。

    综上。二分图最大匹配,当然匈牙利。我爱匈牙利。

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    const int MAXN=10010,MAXM=200010,MAXP=5000;
    bool s_num[MAXN],vis[MAXN];
    int n,m,cnt,ans,head[MAXN],match[MAXN];
    struct edge
    {
    	int nxt,to;
    }e[MAXM];
    void AddEdge(int u,int v)
    {
    	e[++cnt].nxt=head[u];
    	e[cnt].to=v;
    	head[u]=cnt;
    }
    void AddEdges(int u,int v)
    {
    	AddEdge(u,v);
    	AddEdge(v,u);
    }
    bool S_Num(int x)
    {
    	double t;
    	return s_num[x] ? s_num[x] : (t=sqrt(x))==int(t);
    }
    bool DFS(int u)
    {
    	for(int i=head[u],v;i;i=e[i].nxt)
    		if(!vis[v=e[i].to])
    		{
    			vis[v]=1;
    			if(!match[v] || DFS(match[v]))
    			{
    				match[u]=v,match[v]=u;
    				return 1;
    			}
    		}
    	return 0;
    }
    void Print(int x)
    {
    	x+=MAXP;
    	do
    		printf("%d ",x=x-MAXP);
    	while(vis[x]=1,x=match[x]);
    	printf("
    ");
    }
    int main(int argc,char *argv[])
    {
    	scanf("%d",&n);
    	do
    	{
    		int t=++m+MAXP;
    		for(int i=1;i<m;++i)
    			if(S_Num(i+m))
    				AddEdges(i,t);
    		memset(vis,0,sizeof vis);
    		ans+=DFS(t);
    	}
    	while(m-ans<=n);
    	printf("%d
    ",--m);
    	memset(vis,0,sizeof vis);
    	for(int i=1;i<=m;++i)
    		if(!vis[i])
    			Print(i);
    	return 0;
    }
    

    谢谢阅读。

  • 相关阅读:
    线程3 线程池和文件下载服务器
    线程 2
    线程 1
    线程间操作
    编写高质量的代码-------从命名开始
    基于.NET平台常用的框架整理
    消息队列
    我是一个线程
    linux 网络命令
    css hack比较全 --- 转
  • 原文地址:https://www.cnblogs.com/Capella/p/8195728.html
Copyright © 2011-2022 走看看