[網絡流24題]魔術球問題

題目描述

«問題描述:算法

假設有n根柱子,現要按下述規則在這n根柱子中依次放入編號爲1,2,3,...的球。編程

(1)每次只能在某根柱子的最上面放球。網絡

(2)在同一根柱子中,任何2個相鄰球的編號之和爲徹底平方數。spa

試設計一個算法,計算出在n根柱子上最多能放多少個球。例如,在4 根柱子上最多可放11 個球。設計

«編程任務:code

對於給定的n,計算在n根柱子上最多能放多少個球。blog

輸入輸出格式

輸入格式:string

 

第1 行有1個正整數n,表示柱子數。it

 

輸出格式:io

 

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

題解

能夠肯定的是必定要邊枚舉當前要放的球邊跑最大流

兩個加起來是徹底平方的球之間必定是要連邊的。

因爲放的順序從小到大,因此連邊的方向必定是從當前球向已放球

邊的容量均爲1,每次在原網絡上建邊跑最大流,

若是存在最大流,證實當前球能夠放在另外一球上面

不然就要自立門戶了。。。

 

 

若是你單純地按上面的描述建邊,會發現出現了一點小問題。。。

這時候須要用到一個小技巧————拆點

將一個點拆成入點和出點,入點和s,出點和t連邊,入點向出點連邊

完成!

  1 #include<cmath>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 using namespace std;
  7 int n,m,cnt,tot,tp;
  8 int st,ed,ans,num;
  9 int head[200005];
 10 int cur[200005];
 11 int dis[200005];
 12 int pre[200005];
 13 bool usd[200005];
 14 int pr[200005];
 15 struct Edge{
 16     int fr;
 17     int to;
 18     int flw;
 19     int nxt;
 20 }edge[8888888];
 21 void init(){
 22     memset(head,-1,sizeof(head));
 23 }
 24 void addedge(int u,int v,int f){
 25     edge[cnt].fr=u;
 26     edge[cnt].to=v;
 27     edge[cnt].flw=f;
 28     edge[cnt].nxt=head[u];
 29     head[u]=cnt++;
 30     edge[cnt].fr=v;
 31     edge[cnt].to=u;
 32     edge[cnt].nxt=head[v];
 33     head[v]=cnt++;
 34 }
 35 int bfs(int ban){
 36     queue<int>que;
 37     memset(dis,0x3f,sizeof(dis));
 38     que.push(st);dis[st]=1;
 39     while(!que.empty()){
 40         int u=que.front();
 41         que.pop();
 42         for(int i=head[u];i!=-1;i=edge[i].nxt){
 43             int v=edge[i].to;
 44             if(ban==v)continue;
 45             if(!edge[i].flw)continue;
 46             if(dis[v]==0x3f3f3f3f){
 47                 dis[v]=dis[u]+1;
 48                 que.push(v);
 49             }
 50         }
 51     }
 52     return dis[ed]!=0x3f3f3f3f;
 53 }
 54 int dfs(int u,int flw){
 55     if(u==ed)return flw;
 56     int All=0,tmp;
 57     for(int i=cur[u];i!=-1;i=edge[i].nxt){
 58         if(!edge[i].flw)continue;
 59         int v=edge[i].to;cur[u]=i;
 60         if(dis[v]!=dis[u]+1)continue;
 61         if((tmp=dfs(v,min(flw,edge[i].flw)))>0){
 62             pre[v]=u;
 63             edge[i].flw-=tmp;
 64             edge[i^1].flw+=tmp;
 65             flw-=tmp,All+=tmp;
 66             if(!flw)break;
 67         }
 68     }
 69     return All;
 70 }
 71 int dinic(int ban){
 72     int ret=0;
 73     while(bfs(ban)){
 74         memcpy(cur,head,sizeof(cur));
 75         ret+=dfs(st,0x3f3f3f3f);
 76     }
 77     return ret;
 78 }
 79 int main(){
 80     init();ed=200000;
 81     scanf("%d",&n);
 82     while(true){
 83         ans++;
 84         addedge(st,ans*2-1,1);
 85         addedge(ans*2,ed,1);
 86         for(int i=1;i<ans;i++){
 87             int a=sqrt(ans+i);
 88               if(a*a!=ans+i)continue;
 89             addedge(i*2-1,ans*2,1);
 90         }
 91         num+=1-dinic(-1);
 92         if(num>n){
 93             printf("%d\n",ans-1);
 94             dinic(ans*2);
 95             for(int i=1;i<ans;i++){
 96                 usd[(pre[2*i]+1)/2]=true;
 97             }
 98             for(int i=1;i<ans;i++){
 99                 if(!usd[i]){
100                     int now=i;tp=0;
101                     while(now){
102                         pr[++tp]=now;
103                         now=(pre[now*2]+1)/2;
104                     }
105                     for(int i=tp;i>=1;i--){
106                         printf("%d",pr[i]);
107                         if(i!=1)printf(" ");
108                     }
109                     printf("\n");
110                 }
111             }
112             break;
113         }
114     }
115     return 0;
116 }
相關文章
相關標籤/搜索