396. [网络流24题]魔术球问题(简化版
★★☆ 输入文件:balla.in
输出文件:balla.out
简单对比
时间限制:1 s 内存限制:128 MB
问题描述:
假设有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
每一行表示一个柱子上的球
最小路径覆盖=总点数-最大匹配
最大匹配可以用dinic 来求。其实最小路径覆盖数就相当于是柱子数
#include<cstdio> #include<cstring> #include<cmath> #include<queue> using namespace std; const int N=3510; const int INF=1e9; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } struct edge{ int v,nxt,f; }e[N*50]; int hd[N],tot=1; void add_edge(int u,int v,int c){ e[++tot].v=v;e[tot].nxt=hd[u];e[tot].f=c;hd[u]=tot;return; } void insert(int u,int v,int c){ add_edge(u,v,c);add_edge(v,u,0); } int n,m,S,T; int d[N]; bool BFS(){ memset(d,0,sizeof d); queue<int>q; q.push(S); d[S]=1; while(!q.empty()){ int u=q.front();q.pop(); for(int i=hd[u];i;i=e[i].nxt){ int v=e[i].v; if(e[i].f && !d[v]){ d[v]=d[u]+1; q.push(v); } } } return d[T]; } int DFS(int u,int lim){ if(u==T)return lim; int tmp,f=0; for(int i=hd[u];i;i=e[i].nxt){ int v=e[i].v; if(d[v]==d[u]+1&&e[i].f){ tmp=DFS(v,min(lim,e[i].f)); e[i].f-=tmp; e[i^1].f+=tmp; f+=tmp; lim-=tmp; if(!lim)return f; } } d[u]=0; return f; } int Dinic(){ int res=0; while(BFS())res+=DFS(S,INF); return res; } int main(){ freopen("balla.in","r",stdin); freopen("balla.out","w",stdout); n=read();m=0; S=0,T=3201; for(int i=1;i<=1600;i++){ insert(S,i*2-1,1); insert(i*2,T,1); for(int j=1;j<i;j++){ int t=sqrt(j+i); if(t*t==j+i) insert(j*2-1,i*2,1); } m+=Dinic(); if(i-m>n){ printf("%d ",i-1);break; } } return 0; }
线性规划做法
f(n)= (n*n-2)/2+n;//(n mod 2==0)
f(n)= (n*n-1)/2+n;//(n mod 2==1)
#include<cstdio> using namespace std; int n,ans; int main(){ freopen("balla.in","r",stdin); freopen("balla.out","w",stdout); scanf("%d",&n); if(n&1) ans=(n*n-1>>1)+n; else ans=(n*n-2>>1)+n; printf("%d",ans); return 0; }