zoukankan      html  css  js  c++  java
  • [网络流24题]魔术球问题(简化版)

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

    ´数据输入: 
    文件第1 行有 1个正整数n,表示柱子数。 
    ´结果输出: 
    文件的第一行是球数。

    数据规模

    n<=60  保证答案小于1600

    输入文件示例

    4

    输出文件示例

    11

    方案如下

    1 8 
    2 7 9 
    3 6 10 
    4 5 11

    每一行表示一个柱子上的球

    /*
      看到这道题我一下子想到二分答案,拆点建图,然后不会判断了,看了看黄学长的代码,不是很懂。
      然后自己敲了一遍,竟然超时了一个点,我的天!明天接着搞…… 
      
      PS:这道题的学名叫:二分图最小路径覆盖(好高深的样子),意思就是给出一张图,求最少的路径条数,使每个点通过且只通过一次。
      由上面得出:
        1.一个单独的点是一个路径
        2:如果有路径a,b,c。。。。f,g。a为起点,g为终点。那么a到g的点不在与其他点之间存在有向边。
           最小路径覆盖=点数---最大匹配数
      证明:
        1  如果匹配数为0,那么图中没有边,需要n条路径
        2  如果a,b之间连一条边,那么匹配数增1,需要的路径数会减少一,因为a,b之间只需要一条,那么就证明了
      一个最好的利用是 把点分为i与i’点,建立二分图
    */
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #define N 3210
    #define inf 1000000000
    using namespace std;
    int head[N],dis[N],q[N],cnt=1,S,T,flow;
    int cur[N];
    struct node{
        int v,f,pre;
    };node e[N*N];
    void add(int u,int v,int f){
        e[++cnt].v=v;e[cnt].f=f;e[cnt].pre=head[u];head[u]=cnt;
        e[++cnt].v=u;e[cnt].f=0;e[cnt].pre=head[v];head[v]=cnt;
    }
    bool bfs(){
        for(int i=1;i<=T;i++)dis[i]=inf;
        int h=0,t=1;q[1]=S;dis[S]=0;
        while(h<t){
            int u=q[++h];
            for(int i=head[u];i;i=e[i].pre){
                int v=e[i].v;
                if(e[i].f&&dis[u]+1<dis[v]){
                    dis[v]=dis[u]+1;
                    if(v==T)return true;
                    q[++t]=v;
                }
            }
        }
        if(dis[T]==inf)return false;
        return true;
    }
    int dinic(int now,int f){
        if(now==T)return f;
        int w,used=0;
        for(int i=cur[now];i;i=e[i].pre)
            if(dis[e[i].v]==dis[now]+1){
                w=f-used;
                w=dinic(e[i].v,min(w,e[i].f));
                e[i].f-=w;
                e[i^1].f+=w;
                used+=w;
                if(e[i].f)cur[now]=i;
            }
        if(!used)dis[now]=-1;
        return used;
    }
    bool check(int n){
        memset(head,0,sizeof(head));cnt=1;
        S=0;T=n*2+1;
        for(int i=1;i<=n;i++){
            add(S,i,1);add(i+n,T,1);
        }
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++){
                int t=sqrt(i+j);
                if(t*t==i+j)add(i,j+n,1);
            }
        int max_flow=0;
        while(bfs()){
            for(int i=0;i<=T;i++)cur[i]=head[i];
            max_flow+=dinic(S,inf);
        }
        if(flow+max_flow<n)return false;
        return true;
    }
    int main(){
        //freopen("balla.in","r",stdin);
        //freopen("balla.out","w",stdout);
        scanf("%d",&flow);
        if(!flow){
            printf("0");return 0;
        }
        int l=1,r=1600,ans;
        while(l<=r){
            int mid=(l+r)/2;
            if(check(mid))l=mid+1,ans=mid;
            else r=mid-1;
        }
        printf("%d",ans);
        return 0;
    }

    这里说一下超时的原因:dinic被黄学长的完爆了。

    贴一下我原来的代码:

    int dinic(int now,int f){
        if(now==T)return f;
        int rest=f;
        for(int i=head[now];i;i=e[i].pre)
            if(e[i].f&&dis[e[i].v]===dis[now]+1){
                int t=dfs(e[i].v,min(e[i].f,rest));
                if(!t)dis[e[i].v]=0;
                e[i].f-=t;
                e[i^1].f+=t;
                rest-=t;
        }
        return f-rest;
    }

    黄学长的:

    int dinic(int now,int f){
        if(now==T)return f;
        int w,used=0;
        for(int i=cur[now];i;i=e[i].pre)
            if(dis[e[i].v]==dis[now]+1){
                w=f-used;
                w=dinic(e[i].v,min(w,e[i].f));
                e[i].f-=w;
                e[i^1].f+=w;
                used+=w;
                if(e[i].f)cur[now]=i;
            }
        if(!used)dis[now]=-1;
        return used;
    }
  • 相关阅读:
    实时获取浏览器的窗口大小
    char*,wchar_t*,CString和BSTR之间的转换
    Struts2学习(五)
    Struts2学习(四)
    Struts2学习(三)
    Struts2学习(二)
    Struts2学习(一)
    Jsp学习(五)
    Jsp学习(四)
    Jsp学习(三)
  • 原文地址:https://www.cnblogs.com/harden/p/6257834.html
Copyright © 2011-2022 走看看