首页 > 代码库 > [网络流24题]魔术球问题

[网络流24题]魔术球问题

问题描述: 
假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球。 
(1)每次只能在某根柱子的最上面放球。 
(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。 
试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可
放11个球。 
´编程任务: 
对于给定的n,计算在 n根柱子上最多能放多少个球。

´数据输入: 
文件第1 行有 1个正整数n,表示柱子数。 
´结果输出: 
文件的第一行是球数。

数据规模

n<=60  保证答案小于1600

输入文件示例

4

输出文件示例

11

方案如下

1 8 
2 7 9 
3 6 10 
4 5 11

每一行表示一个柱子上的球

 

这应该是有spj的

虽然是 网络流 但是贪心也能过

详解在 dinic中

技术分享
 1 /* 2     尽管是网络流24题之一  3     我还是忍不住用了贪心  4 */ 5 #include <cmath> 6 #include <ctype.h> 7 #include <cstdio> 8  9 const int MAXN=1010;10 11 int tot,n;12 13 int a[MAXN][MAXN];14 15 inline void read(int&x) {16     register char c=getchar();17     for(x=0;!isdigit(c);c=getchar());18     for(;isdigit(c);x=x*10+c-48,c=getchar());19 }20 21 inline bool check(int x) {22     int p=sqrt(x);23     if(p*p==x) return true;24     else return false;25 }26 27 int hh() {28     freopen("balla.in","r",stdin);29     freopen("balla.out","w",stdout);30     read(n);31     int it=1;32     a[++tot][++a[tot][0]]=1;33     while(true) {34         int flag=0;++it;35         for(int i=1;i<=tot;++i) {36             int t=it+a[i][a[i][0]];37             if(check(t)) a[i][++a[i][0]]=it,flag=1;38             if(flag) break;39         }40         if(flag) continue;41         tot++;42         a[tot][++a[tot][0]]=it;43         if(tot>n) break;44     }45     printf("%d\n",it-1);46 /*    for(int i=1;i<tot;++i) {47         for(int j=1;j<=a[i][0];++j)48           printf("%d ",a[i][j]);49         printf("\n");50     }*/51     return 0;52 } 53 54 int sb=hh();55 int main() {;}
贪心
技术分享
 1 /* 2     二分图匹配  3 */ 4 #include <cstdio> 5 #include <cstring>  6  7 const int MAXN=4001; 8 const int MAXM=30010; 9 10 int n,mark[MAXM],vist[MAXM];11 12 bool c[MAXN],vis[MAXN];13 14 struct PLU {15     int to;16     int next;17 };18 PLU t[MAXM];19 20 int head[MAXN],tot=1;21 22 inline void add(int x,int y) {23     t[++tot].to=y;24     t[tot].next=head[x];25     head[x]=tot; 26 } 27 28 bool find(int x) {29     for(int i=head[x];i!=-1;i=t[i].next) {30         int to=t[i].to;31         if(!vis[to]) {32             vis[to]=true;33             if(!mark[to]||find(mark[to])) {34                 vist[x]=to,mark[to]=x;35                 return true;36             }37         } 38     }39     return false;40 }41 42 int hh() {43     freopen("balla.in","r",stdin);44     freopen("balla.out","w",stdout);45     int ans=0;46     scanf("%d",&n);47     memset(head,-1,sizeof head);48     for(int i=1;i<=63;++i) c[i*i]=true;49     for(int i=1;i<=1600;++i) {50         for(int j=1;j<i;++j)51             if(c[i+j]) add(i,j);52         for(int j=1;j<=i;++j) {53             if(!vist[j]) {54                 memset(vis,false,sizeof vis);55                 if(find(j)) ++ans;56             } 57         }58         if(i-ans>n) {59             printf("%d\n",i-1);60             goto END; 61         } 62     }63 END:64     return 0;65 }66 67 int sb=hh();68 int main() {;}
匈牙利算法
技术分享
  1 /*  2     对于每一个 x+y=i^2(x<y)  3     依照题意我们知道 x,y 都能且只能使用一次  4     所以我们可以把每一个数字 x 拆成 x1 和 x0  5     其中 x1 加上一个比 x1 小的数字构成一个完全平方数  6     x0 加上一个比 x0 大的数构成一个完全平方数  7     再把所有的 (y0,z1)(y0+z1=i^2,y0<z1,i∈N+)   8     之间连一条有向边就是一个二分图匹配的问题了  9      10     新增一个源 S 和汇 T  11     把当前的整数 x 拆成 x0 和 x1  12     连接一条容量为 1   从 S 到 x0 的有向边  13     连接一条容量为 1   从 x1 到 T 的有向边  14      连接一条容量为 1   从 x0 到 k(x0+k=i^2,k∈N+,i∈N+) 的有向边 15 */ 16 #include <queue> 17 #include <cmath> 18 #include <cstring> 19 #include <cstdio> 20  21 const int MAXN=40010; 22 const int INF=0x7fffffff; 23  24 struct data { 25     int to; 26     int next; 27     int val; 28 };  29 data e[MAXN]; 30  31 int head[MAXN],cur[MAXN],tot=1; 32  33 int depth[MAXN]; 34  35 int src,decc,n; 36  37 std::queue<int>q; 38  39 inline void add(int x,int y,int z) { 40     e[++tot].to=y; 41     e[tot].val=z; 42     e[tot].next=head[x]; 43     head[x]=tot; 44 } 45  46 inline int min(int a,int b) { 47     return a<b?a:b; 48 }  49  50 bool bfs() { 51     for(int i=0;i<=decc;++i) cur[i]=head[i],depth[i]=-1; 52     while(!q.empty()) q.pop(); 53     q.push(src); 54     depth[src]=0; 55     while(!q.empty()) { 56         int u=q.front();  57         q.pop(); 58         for(int i=head[u];i!=-1;i=e[i].next) { 59             int to=e[i].to; 60             if(e[i].val&&depth[to]==-1) { 61                 depth[to]=depth[u]+1; 62                 q.push(to); 63                 if(to==decc) return true; 64             } 65         } 66     } 67     return false; 68 } 69  70 int dfs(int now,int flow) { 71     if(now==decc) return flow; 72     int used=0,delat; 73     for(int & i=cur[now];i!=-1;i=e[i].next) { 74         int to=e[i].to; 75         if(e[i].val&&depth[to]==depth[now]+1) { 76             delat=flow-used; 77             delat=dfs(to,min(delat,e[i].val)); 78             e[i].val-=delat; 79             e[i^1].val+=delat; 80             used+=delat; 81             if(used==flow) break;  82         } 83     } 84     if(!used) depth[now]=-1; 85     return used; 86 } 87  88 int hh() { 89     freopen("balla.in","r",stdin); 90     freopen("balla.out","w",stdout); 91     int ans=0,it=0; 92     memset(head,-1,sizeof head); 93     decc=1610*2; 94     scanf("%d",&n); 95     while(true) { 96         ++ans,++it; 97         for(int i=1;i<it;++i) 98           if(sqrt(i+it)==int(sqrt(i+it)))  99             add(i,it+1600,1),add(it+1600,i,0);100         add(src,it,1);add(it,src,0);101         add(it+1601,decc,1);add(decc,it+1601,0);102         while(bfs())103           ans-=dfs(src,INF);104         if(ans>n) break;105     }106     printf("%d\n",it-1);107     return 0;108 }109 110 int sb=hh();111 int main() {;}
dinic

 

[网络流24题]魔术球问题