• 魔术球问题


    首先诚挚感谢BYvoid大神博客里提供的好题和数据

    此为线性规划与网络流24题的第四题。

    «问题描述:
    假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,¼的球。
    (1)每次只能在某根柱子的最上面放球。
    (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。
    试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可
    放11 个球。
    «编程任务:
    对于给定的n,计算在n根柱子上最多能放多少个球。
    «数据输入:
    由文件input.txt提供输入数据。文件第1 行有1个正整数n,表示柱子数。
    «结果输出:
    程序运行结束时,将n 根柱子上最多能放的球数以及相应的放置方案输出到文件
    output.txt中。文件的第一行是球数。接下来的n行,每行是一根柱子上的球的编号。
    输入文件示例 输出文件示例
    input.txt output.txt
    4     11
         1 8
           2 7 9
         3 6 10
         4 5 11

     建模分析:

    实际上是最小路径覆盖问题,存在有向边a->b的条件是 (a<b) a+b为完全平方数.

    我用匈牙利和dinic两种办法做了下。dinic:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<queue>
      5 #include<iostream>
      6 #define rep(i,a,b) for(int i=a;i<+b;++i)
      7 using namespace std;
      8 const int MAXN=5010;
      9 const int maxn=1000;
     10 const int INF=~0U>>1;
     11 int n,f,tot,S,T;
     12 int h[MAXN*2];
     13 int square[MAXN],pointer[MAXN*2],que[MAXN],path[MAXN];
     14 bool visit[MAXN];
     15 void square_number()
     16 {
     17     square[0]=maxn;
     18     rep(i,1,maxn)
     19     {
     20         square[i]=i*i;
     21     }
     22 }
     23 struct edge{
     24     int to,next;
     25     int cap,f;
     26     int op;
     27 }edge[MAXN*100];
     28 void addedge(int a,int b)
     29 {
     30     edge[tot].to=b;
     31     edge[tot].next=pointer[a];
     32     edge[tot].cap=1;
     33     edge[tot].op=tot^1;
     34     edge[tot].f=0;
     35     pointer[a]=tot;
     36     tot++;
     37     edge[tot].to=a;                 //建立反向边
     38     edge[tot].next=pointer[b];
     39     edge[tot].cap=0;
     40     edge[tot].op=tot^1;
     41     edge[tot].f=0;
     42     pointer[b]=tot;
     43     tot++;
     44 }
     45 void newpoint(int k)
     46 {
     47     rep(i,1,square[0])
     48     {
     49         if(square[i]>=2*k) break;
     50         if(square[i]>k)
     51         {
     52             addedge(square[i]-k,MAXN+k);
     53         }
     54     }
     55     addedge(S,k);
     56     addedge(MAXN+k,T);
     57 }
     58 void Input()
     59 {
     60     scanf("%d",&n);
     61     memset(pointer,-1,sizeof(pointer));
     62     S=0;T=2*MAXN-1;
     63     square_number();
     64 }
     65 
     66 bool dinic_restruct()       //bfs建层次图
     67 {
     68     memset(h,-1,sizeof(h));
     69     queue <int>q;
     70     h[S]=0;
     71     q.push(S);
     72     while(!q.empty())
     73     {
     74         int u=q.front();q.pop();
     75         for(int j=pointer[u];j!=-1;j=edge[j].next)
     76         {
     77             int v=edge[j].to;
     78             if(h[v]==-1&&edge[j].cap-edge[j].f)
     79             {
     80                 h[v]=h[u]+1;
     81                 q.push(v);
     82                 if(v==T) return true;
     83             }
     84         }
     85     }
     86     return false;
     87 
     88 }
     89 void dinic_augment()            //dfs找增广路
     90 {
     91     int Stop=1;
     92     que[Stop]=S;
     93     while(Stop)
     94     {
     95         int u=que[Stop];
     96         if(u!=T)
     97         {
     98             int j;
     99             for(j=pointer[u];j!=-1;j=edge[j].next)
    100             {
    101                 int v=edge[j].to;
    102                 if(h[v]==h[u]+1&&edge[j].cap-edge[j].f>0)
    103                 {
    104                     que[++Stop]=v;
    105                     break;
    106                 }
    107             }
    108             if(j!=-1)
    109             {
    110                 path[Stop]=j;       //记录边的序号
    111             }
    112             else            //回退
    113             {
    114                 Stop--;
    115                 h[u]=-1;
    116             }
    117         }
    118         else
    119         {
    120             int flow=INF;
    121             for(int j=Stop;j>=2;--j)
    122             {
    123                 int &tmp=path[j];
    124                 if(edge[tmp].cap-edge[tmp].f<flow) {
    125                         flow=edge[tmp].cap-edge[tmp].f;
    126                 }
    127             }
    128            // printf("flow=%d f=%d
    ",flow,f);
    129             f+=flow;
    130             for(int j=Stop;j>=2;--j)
    131             {
    132                 int &tmp=path[j];
    133                 edge[tmp].f+=flow;
    134                 edge[tmp^1].f-=flow;
    135                 if(edge[tmp].cap-edge[tmp].f==0) Stop=j-1;            }
    136         }
    137     }
    138 }
    139 void Dinic(int i)
    140 {
    141     newpoint(i);
    142     while(dinic_restruct())
    143     {
    144         dinic_augment();
    145     }
    146 }
    147 void Pout(int ans)
    148 {
    149     printf("%d
    ",ans);
    150     memset(path,0,sizeof(path));
    151     rep(i,1,ans)
    152     {
    153         for(int j=pointer[i];j!=-1;j=edge[j].next)
    154         {
    155             if(edge[j].f==1&&edge[j].to!=S)
    156             {
    157                     path[i]=edge[j].to;
    158                     break;
    159             }
    160         }
    161     }
    162     rep(i,1,ans)
    163     {
    164         int t=i;
    165         if(!visit[i])
    166         {
    167             while(path[t])
    168             {
    169                 printf("%d ",t);
    170                 t=path[t]-MAXN;
    171                 visit[t]=1;
    172             }
    173             printf("%d
    ",t);
    174         }
    175     }
    176 }
    177 void work()
    178 {
    179     f=0;
    180     rep(i,1,maxn*maxn)
    181     {
    182         Dinic(i);
    183         if(i-f>n)
    184         {
    185             Pout(i-1);
    186             break;
    187         }
    188     }
    189 }
    190 int main()
    191 {
    192     freopen("ball10.in","r",stdin);
    193     Input();
    194     work();
    195     return 0;
    196 }

    匈牙利:

      1 #include<cstdio>
      2 #include<cstring>
      3 #define rep(i,a,b) for(int i=a;i<=b;++i)
      4 using namespace std;
      5 const int MAXN=2010;
      6 const int maxn=1000;
      7 int graph[MAXN][MAXN];          //邻接表建图
      8 int match[MAXN];
      9 int visit[MAXN];
     10 int path[MAXN];
     11 int square[maxn+10];
     12 int n,q,S,T,f,z;
     13 void square_number()
     14 {
     15     square[0]=maxn;
     16     rep(i,1,maxn)
     17     {
     18         square[i]=i*i;
     19     }
     20 }
     21 void newpoint(int k)
     22 {
     23     rep(i,1,square[0])
     24     {
     25         if(square[i]>=2*k) break;
     26         if(square[i]>k)
     27         {
     28             int t=square[i]-k;
     29             graph[t][++graph[t][0]]=k;
     30         }
     31     }
     32 
     33 
     34 }
     35 void init()
     36 {
     37     f=0;
     38     S=0;T=2*MAXN-1;
     39     square_number();
     40     scanf("%d",&n);
     41 }
     42 void pout()
     43 {
     44     printf("%d
    ",q-1);
     45     rep(i,1,q-1)
     46     {
     47         int  t=i;
     48         if(!visit[i])
     49         {
     50 
     51             while(path[t]) t=path[t];
     52             while(match[t])
     53             {
     54                 visit[t]=1;
     55                 printf("%d ",t);
     56                 t=match[t];
     57             }
     58             printf("%d
    ",t);
     59         }
     60     }
     61 
     62 }
     63 bool crosspath(int k)
     64 {
     65     rep(i,1,graph[k][0])
     66     {
     67         int &tmp=graph[k][i];
     68         if(!visit[tmp])
     69         {
     70             visit[tmp]=1;
     71             if(match[tmp]==0||match[tmp]!=k&&crosspath(match[tmp]))
     72             {
     73                 match[tmp]=k;
     74               //  printf("k=%d tmp=%d f=%d q=%d z=%d
    ",k,tmp,f,q,z);
     75                 path[k]=tmp;
     76                 return true;
     77             }
     78         }
     79     }
     80     return false;
     81 }
     82 void hungary()
     83 {
     84     for(q=1;q<=maxn*maxn;++q)
     85     {
     86         newpoint(q);
     87         for(z=1;z<=q-1;++z)
     88         {
     89             if(!path[z]&&crosspath(z))      //如果这个点还是单身就试试能不能从它出发找到一条交替路
     90             {
     91                     f++;
     92                    // rep(j,1,q-1)
     93                    // printf("q=%d match[%d]=%d f=%d
    ",q,j+MAXN,match[j],f);
     94             }
     95             memset(visit,0,sizeof(visit));
     96         }
     97         if(q-f>n)           //注意:虽然输出的时候跑过一遍q+1的流程,但match数组没有更新过,因为q+1轮中f必然没有+1,从而crosspath一直在返回0
     98         {
     99             pout();
    100             break;
    101         }
    102     }
    103 
    104 }
    105 
    106 int main()
    107 {
    108     freopen("ball0.in","r",stdin);
    109     init();
    110     hungary();
    111     return 0;
    1
  • 相关阅读:
    My97DatePicker控件显示时分秒
    【servlet学习1】使用eclipse+tomcat开发servlet示例
    JNI之JAVA调用C++接口
    关闭页面,window.onunload事件未执行的原因
    java finally块执行时机分析
    c# IL 指令集
    java 字节码指令集
    Linux可插拔认证模块(PAM)的配置文件、工作原理与流程
    常用的Linux可插拔认证模块(PAM)应用举例(一)
    开始我的博客旅途
  • 原文地址:https://www.cnblogs.com/zhixingr/p/7026700.html
Copyright © 2020-2023  润新知