【网络流24题】魔术球问题
2014年3月7日3,5344
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 }
时间: 2024-11-05 15:56:15