网络流24题魔术球问题(最小不相交路径覆盖)

Posted Kaiser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流24题魔术球问题(最小不相交路径覆盖)相关的知识,希望对你有一定的参考价值。

【网络流24题】魔术球问题

Description

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

编程任务:
对于给定的n,计算在n根柱子上最多能放多少个球。

Input Format

文件第1 行有1个正整数n,表示柱子数。

Output Format

程序运行结束时,将n 根柱子上最多能放的球数以及相应的放置方案输出。文件的第一行是球数。接下来的n行,每行是一根柱子上的球的编号。

Sample Inpu

 4

Sample Output

11
1 8
2 7 9
3 6 10
4 5 11

 

题解:这道题就是小的必须在大的下面,所以保证了DAG的性质。

如果a,b(a<b)并且a+b是一个平方数。

那么a-->b连一条边,那么问题是不是转化为,一个DAG最少需要多少条路径(不想交),可以

完全覆盖,如果超过了n则不行。

所以维护一下网络流,codevs上没开spj,路径方面处理一下。

 

  1 #include<cstring>
  2 #include<cmath>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<iostream>
  6 #include<queue>
  7 
  8 #define N 10007
  9 #define M 200007
 10 #define INF 1000000007
 11 using namespace std;
 12 inline int read()
 13 {
 14     int x=0,f=1;char ch=getchar();
 15     while(ch<0||ch>9){if (ch==-)f=-1;ch=getchar();}
 16     while(ch>=0&&ch<=9){x=(x<<3)+(x<<1)+ch-0;ch=getchar();}
 17     return x*f;
 18 }
 19 
 20 int n,S,T,ans,s;
 21 int cnt=1,head[N],rea[M],val[M],next[M];
 22 int dis[N],to[N],flag[N];
 23 
 24 void add(int u,int v,int fee)
 25 {
 26     next[++cnt]=head[u];
 27     head[u]=cnt;
 28     rea[cnt]=v;
 29     val[cnt]=fee;
 30 }
 31 bool bfs()
 32 {
 33     for (int i=1;i<=T;i++)dis[i]=0;
 34     dis[S]=1;queue<int>q;q.push(S);
 35     while(!q.empty())
 36     {
 37         int u=q.front();q.pop();
 38         for (int i=head[u];i!=-1;i=next[i])
 39         {
 40             int v=rea[i],fee=val[i];
 41             if (!dis[v]&&fee>0)
 42             {
 43                 dis[v]=dis[u]+1;
 44                 if (v==T) return 1;
 45                 q.push(v);
 46             }
 47         }
 48     }
 49     return 0;
 50 }
 51 int dfs(int u,int MF)
 52 {
 53     int res=0;
 54     if (u==T||MF==0) return MF;
 55     for (int i=head[u];i!=-1;i=next[i])
 56     {
 57         int v=rea[i],fee=val[i];
 58         if (dis[v]!=dis[u]+1) continue;
 59         int x=dfs(v,min(MF,fee));
 60         if (x)
 61         {
 62             val[i]-=x,val[i^1]+=x;
 63             MF-=x,res+=x;
 64             if (MF==0) return res;
 65         }
 66     }
 67     if (!res) dis[u]=0;
 68     return res;
 69 }
 70 void Dinic()
 71 {
 72     int res=0;
 73     while(bfs())
 74     {
 75         int x=dfs(S,INF);
 76         while(x)
 77         {
 78             res+=x;
 79             x=dfs(S,INF);
 80         }
 81     }
 82     ans-=res;
 83 }
 84 int main()
 85 {
 86     memset(head,-1,sizeof(head));
 87     n=read();
 88     S=0,T=10001;
 89     while(true)
 90     {
 91         ans++,s++;
 92         for (int i=1;i<s;i++)
 93             if (sqrt(i+s)==(int)(sqrt(i+s))) add(i,s+5000,1),add(s+5000,i,0);
 94         add(S,s,1),add(s,S,0),add(s+5000,T,1),add(T,s+5000,0);
 95         Dinic();
 96         if (ans>n) break;    
 97     }
 98     printf("%d\n",s-1);
 99     for (int i=1;i<s;i++)
100         for (int j=head[i];j!=-1;j=next[j])
101         {
102             int v=rea[j],fee=val[j];
103             if (!fee) {to[i]=v-5000;break;}
104         }
105     for (int i=1;i<s;i++)
106     {
107         if (flag[i]) continue;
108         int t=i;
109         while(t!=-5000)
110         {
111             flag[t]=1;
112             printf("%d ",t);
113             t=to[t];
114         }
115         printf("\n");
116     }//十分巧妙的构思,转化问题十分优秀。 
117 }

 

 

以上是关于网络流24题魔术球问题(最小不相交路径覆盖)的主要内容,如果未能解决你的问题,请参考以下文章

网络流24题

网络流24题-题目总结

[loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流

LiberOJ 6003. 「网络流 24 题」魔术球 贪心或者最小路径覆盖

[luoguP2765] 魔术球问题(最大流—最小不相交路径覆盖)

[网络流24题]魔术球问题