1. 程式人生 > >【網絡流24題】魔術球問題(最小不相交路徑覆蓋)

【網絡流24題】魔術球問題(最小不相交路徑覆蓋)

define sam 十分 def sizeof name ++ res align

【網絡流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題】魔術球問題(最小不相交路徑覆蓋)