1. 程式人生 > >【網絡流24題】魔術球問題 二分答案+最小路徑覆蓋

【網絡流24題】魔術球問題 二分答案+最小路徑覆蓋

cnblogs for getchar() str logs math 等於 active rip

Description

假設有n根柱子,現要按下述規則在這n根柱子中依次放入編號為1,2,3,...的球。 (1)每次只能在某根柱子的最上面放球。 (2)在同一根柱子中,任何2個相鄰球的編號之和為完全平方數。 試設計一個算法,計算出在n根柱子上最多能放多少個球。例如,在4 根柱子上最多可 放11 個球。 編程任務: 對於給定的n,計算在n根柱子上最多能放多少個球。

Input

由文件input.txt提供輸入數據。文件第1 行有1個正整數n(n<=55),表示柱子數。

Output

程序運行結束時,將n 根柱子上最多能放的球數以及相應的放置方案輸出到文件 output.txt中。文件的第一行是球數。接下來的n行,每行是一根柱子上的球的編號。 Sample Input
4

Sample Output

11 1 8 2 7 9 3 6 10 4 5 11 題解: 二分最大球數。 用這幾個球來做最小路徑覆蓋 能夠滿足加起來等於平方數的就連邊(註意 i<j).
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 using namespace std;
  7 const int N=5005,INF=1999999999
; 8 int gi(){ 9 int str=0;char ch=getchar(); 10 while(ch>9 || ch<0)ch=getchar(); 11 while(ch>=0 && ch<=9)str=str*10+ch-0,ch=getchar(); 12 return str; 13 } 14 int k,head[N],num=1,S=0,T; 15 struct Lin{ 16 int next,to,dis; 17 }a[N*10]; 18 void init(int
x,int y,int dis){ 19 a[++num].next=head[x]; 20 a[num].to=y; 21 a[num].dis=dis; 22 head[x]=num; 23 a[++num].next=head[y]; 24 a[num].to=x; 25 a[num].dis=0; 26 head[y]=num; 27 } 28 bool pd(int x,int y){ 29 int tmp=sqrt(x+y); 30 if(tmp*tmp==x+y)return true; 31 return false; 32 } 33 int q[N],dep[N]; 34 bool bfs() 35 { 36 memset(dep,0,sizeof(dep)); 37 int t=0,sum=1,u,x; 38 q[1]=S;dep[S]=1; 39 while(t!=sum) 40 { 41 x=q[++t]; 42 for(int i=head[x];i;i=a[i].next){ 43 u=a[i].to; 44 if(a[i].dis<=0 || dep[u])continue; 45 dep[u]=dep[x]+1;q[++sum]=u; 46 } 47 } 48 return dep[T]; 49 } 50 int dfs(int x,int flow) 51 { 52 if(x==T || !flow)return flow; 53 int u,tmp,tot=0; 54 for(int i=head[x];i;i=a[i].next){ 55 u=a[i].to; 56 if(dep[u]!=dep[x]+1 || a[i].dis<=0)continue; 57 tmp=dfs(u,min(flow,a[i].dis)); 58 a[i].dis-=tmp;a[i^1].dis+=tmp; 59 tot+=tmp;flow-=tmp; 60 if(!flow)break; 61 } 62 return tot; 63 } 64 int maxflow() 65 { 66 int tot=0,tmp; 67 while(bfs()){ 68 tmp=dfs(S,INF); 69 while(tmp)tot+=tmp,tmp=dfs(S,INF); 70 } 71 return tot; 72 } 73 void Clear(){ 74 memset(head,0,sizeof(head)); 75 num=1; 76 } 77 bool check(int n) 78 { 79 T=(n<<1)+1; 80 for(int i=1;i<=n;i++)init(S,i,1),init(i+n,T,1); 81 for(int i=1;i<=n;i++) 82 for(int j=i+1;j<=n;j++){ 83 if(pd(i,j)) 84 init(i,j+n,INF); 85 } 86 int tp=n-maxflow(); 87 return tp<=k; 88 } 89 bool vis[N];int ans=0; 90 void putans(int x) 91 { 92 printf("%d ",x); 93 vis[x]=true; 94 for(int i=head[x];i;i=a[i].next){ 95 if(a[i].dis==INF-1)putans(a[i].to-ans); 96 } 97 } 98 int main() 99 { 100 k=gi();int l=k,r=2000,mid; 101 while(l<=r){ 102 mid=(l+r)>>1; 103 if(check(mid))ans=mid,l=mid+1; 104 else r=mid-1; 105 Clear(); 106 } 107 check(ans); 108 printf("%d\n",ans); 109 for(int i=1;i<=ans;i++){ 110 if(vis[i])continue; 111 putans(i); 112 printf("\n"); 113 } 114 return 0; 115 }

【網絡流24題】魔術球問題 二分答案+最小路徑覆蓋