1. 程式人生 > >[loj #6003]「網絡流 24 題」魔術球 二分圖最小路徑覆蓋,網絡流

[loj #6003]「網絡流 24 題」魔術球 二分圖最小路徑覆蓋,網絡流

sqrt ted -html hide next http osi header col

#6003. 「網絡流 24 題」魔術球

內存限制:256 MiB時間限制:1000 ms標準輸入輸出 題目類型:傳統評測方式:Special Judge 上傳者: 匿名 提交提交記錄統計討論測試數據

題目描述

假設有 n nn 根柱子,現要按下述規則在這 n nn 根柱子中依次放入編號為 1,2,3,4,? 1, 2, 3, 4, \cdots1,2,3,4,? 的球。

  1. 每次只能在某根柱子的最上面放球。
  2. 在同一根柱子中,任何 2 22 個相鄰球的編號之和為完全平方數。

試設計一個算法,計算出在 n nn 根柱子上最多能放多少個球。

輸入格式

文件第 1 11 行有 1 11 個正整數 n nn,表示柱子數。

輸出格式

第一行是球數。接下來的 n nn 行,每行是一根柱子上的球的編號。

樣例

樣例輸入

4

樣例輸出

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

數據範圍與提示

1≤n≤55 1 \leq n \leq 551n55

把每個柱子看成一條路徑,跑最小路徑覆蓋。

技術分享圖片
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<cmath>
 6
#include<algorithm> 7 using namespace std; 8 struct data { 9 int to,next,f; 10 }e[100005]; 11 int head[5005],cnt; 12 void add(int u,int v,int f){e[cnt].to=v;e[cnt].next=head[u];e[cnt].f=f;head[u]=cnt++;} 13 int n,m,s,t; 14 bool vis[5005]; 15 int q[5005],dis[5005]; 16 bool bfs() { 17 memset(dis,-57
,sizeof(dis)); 18 int h=0,tail=1; 19 q[h]=t; 20 dis[t]=0; 21 while(h!=tail) { 22 int now=q[h++];if(h==5000) h=0; 23 for(int i=head[now];i>=0;i=e[i].next) { 24 if(dis[e[i].to]>-100000||!e[i^1].f) continue; 25 dis[e[i].to]=dis[now]-1; 26 q[tail++]=e[i].to;if(tail==5000) tail=0; 27 } 28 } 29 return dis[s]>=-100000; 30 } 31 int dfs(int now,int a) { 32 int f=0,flow=0; 33 if(now==t) return a; 34 for(int i=head[now];i>=0;i=e[i].next) { 35 int to=e[i].to; 36 if(dis[to]==dis[now]+1&&e[i].f>0) { 37 f=dfs(to,min(a,e[i].f)); 38 flow+=f; 39 e[i].f-=f; 40 e[i^1].f+=f; 41 a-=f; 42 if(a==0) break; 43 } 44 } 45 return flow; 46 } 47 int num=0; 48 int ans=0; 49 int sum=0; 50 int dinic() { 51 while(bfs()) { 52 sum+=dfs(s,2147483647); 53 } 54 return num-sum; 55 } 56 57 bool work() { 58 num++; 59 add(s,num,1);add(num,s,0);add(num+2500,t,1);add(t,num+2500,0); 60 for(int i=1;i<num;i++) { 61 if(sqrt(i+num)==(int)sqrt(i+num)) add(num,i+2500,1),add(i+2500,num,0); 62 } 63 if(dinic()<=n) return 1; 64 else return 0; 65 } 66 void pout(int x) { 67 vis[x]=1; 68 printf("%d ",x); 69 for(int i=head[x+2500];i>=0;i=e[i].next) { 70 if(e[i].f==1&&!vis[e[i].to]){pout(e[i].to);return;} 71 } 72 return; 73 } 74 int main() { 75 memset(head,-1,sizeof(head)); 76 scanf("%d",&n); 77 s=0,t=5001; 78 while(work()) ; 79 num--; 80 printf("%d\n",num); 81 memset(vis,0,sizeof(vis)); 82 vis[s]=vis[t]=1; 83 for(int i=1;i<=num;i++) { 84 if(!vis[i]){pout(i);printf("\n");} 85 } 86 }
View Code

[loj #6003]「網絡流 24 題」魔術球 二分圖最小路徑覆蓋,網絡流