【网络流24题】魔术球(最小路径覆盖+枚举)
来源:互联网 发布:tomcat9启动 源码解析 编辑:程序博客网 时间:2024/06/11 02:53
传送门
魔术球
题意:向n根柱子里依次放置编号连续且递增的球。且同一根柱子里相邻两球编号和为完全平方数。求在这n根柱子里最多能放多少球。
I think
模型转化:视n为路径覆盖数,枚举放入环中数的数量,转化为上一题的路径覆盖问题。
由于“依次”放球,所以构造出的一定是有向无环图。
Code
每次重新建边,不加优化的版本
#include<vector>#include<cstdio>#include<queue>#include<cmath>using namespace std;const int sm = 4000;const int sn = 127200;const int C = 1600;const int Inf = 0x3f3f3f3f;int a,N,S=3201,T=3202;int cnt,sum,ans,tot=1;int to[sn],nxt[sn],hd[sm],w[sn];int p[sm],lev[sm],cur[sm]; bool pf[3605];vector<int>now[sm>>1],c[sm];int Min(int x,int y) { return x<y?x:y; }void Add(int u,int v) { to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot,w[tot]=1; to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot,w[tot]=0;} void Init(int *g) { for(int i=1;i<=a;++i) g[i]=0; for(int i=C+1;i<=C+a;++i) g[i]=0; g[S]=g[T]=0;}bool Bfs() { queue<int>q; int t; q.push(S); Init(lev);lev[S]=1; while(!q.empty()) { t=q.front(),q.pop(); for(int i=hd[t];i;i=nxt[i]) if(!lev[to[i]]&&w[i]) { lev[to[i]]=lev[t]+1; if(to[i]==T) return 1; q.push(to[i]); } } return 0;}int Dfs(int x,int mx) { if(x==T||!mx) return mx; int f; for(int i=cur[x]?cur[x]:hd[x];i;i=nxt[i]) { cur[x]=i; if(lev[to[i]]==lev[x]+1&&w[i]) { if(f=Dfs(to[i],Min(mx,w[i]))) return w[i]-=f,w[i^1]+=f,f; } } return 0;} int Dinic() { int f,Flw=0; while(Bfs()) { Init(cur); while(f=Dfs(S,Inf)) Flw+=f; } return Flw;}void Pre() { for(int i=hd[S];i;i=nxt[i]) if(!w[i]) { for(int j=hd[to[i]];j;j=nxt[j]) if(!w[j]&&to[j]!=S) { p[to[j]]=to[i]; p[to[i]]=to[j]; break; } }}int main() { int u,v,ret=0; scanf("%d",&N); for(int i=1;i<=60;++i) pf[i*i]=1; while(1) { ++a;//枚举 Init(hd); for(int i=1;i<a;++i) if(pf[i+a]) c[i].push_back(a); tot=1; for(int i=1;i<=a;++i) {//重新建边 Add(S,i),Add(i+C,T); for(int j=0;j<c[i].size();++j) Add(i,c[i][j]+C); } ret=Dinic(); if(a-ret==N) {//预备储存答案直到a-ret==N+1,此时取到最大答案 Pre(); ans=sum=0; for(int i=1;i<=a;++i) if(p[i]) { now[++sum].clear(); now[sum].push_back(u=i); do { v=u,u=p[u]-C; now[sum].push_back(u); p[v]=0; }while(p[u]); ans+=now[sum].size(); } } else if(a-ret==N+1) break; } printf("%d\n",ans); for(int i=1;i<=sum;++i) { printf("%d",now[i][0]); for(int j=1;j<now[i].size();++j) printf(" %d",now[i][j]); putchar(10); } return 0;}
每次只在Dinic之后更新容量的优化版本,虽说从实际运行时间上来看优化不大,还是要mark一下这种将数组指定位复制的memcpy用法。
复制b[u..v]到a[x..y](其中y-x==v-u)memcpy(a+x, b+u, sizeof(int)*(v-u+1));
#include<vector>#include<cstdio>#include<cstring>#include<queue>#include<cmath>using namespace std;const int sm = 4000;const int sn = 127200;const int C = 1600;const int Inf = 0x3f3f3f3f;int a,N,S=3201,T=3202;int cnt,sum,ans,tot=1;int to[sn],nxt[sn],hd[sm],w[sn],_w[sn];int p[sm],lev[sm],cur[sm]; bool pf[3605];vector<int>now[sm>>1],c[sm];int Min(int x,int y) { return x<y?x:y; }void Add(int u,int v) { to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot,_w[tot]=w[tot]=1; to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot,_w[tot]=w[tot]=0;} void Init(int *g) { for(int i=1;i<=a;++i) g[i]=0; for(int i=C+1;i<=C+a;++i) g[i]=0; g[S]=g[T]=0;}bool Bfs() { queue<int>q; int t; q.push(S); Init(lev);lev[S]=1; while(!q.empty()) { t=q.front(),q.pop(); for(int i=hd[t];i;i=nxt[i]) if(!lev[to[i]]&&w[i]) { lev[to[i]]=lev[t]+1; if(to[i]==T) return 1; q.push(to[i]); } } return 0;}int Dfs(int x,int mx) { if(x==T||!mx) return mx; int f; for(int i=cur[x]?cur[x]:hd[x];i;i=nxt[i]) { cur[x]=i; if(lev[to[i]]==lev[x]+1&&w[i]) { if(f=Dfs(to[i],Min(mx,w[i]))) return w[i]-=f,w[i^1]+=f,f; } } return 0;} int Dinic() { int f,Flw=0; while(Bfs()) { Init(cur); while(f=Dfs(S,Inf)) Flw+=f; } return Flw;}void Pre() { for(int i=hd[S];i;i=nxt[i]) if(!w[i]) { for(int j=hd[to[i]];j;j=nxt[j]) if(!w[j]&&to[j]!=S) { p[to[j]]=to[i]; p[to[i]]=to[j]; break; } }}int main() { int u,v,ret=0; scanf("%d",&N); for(int i=1;i<=60;++i) pf[i*i]=1; while(1) { ++a; memcpy(w+2,_w+2,sizeof(int)*(tot-1)); for(int i=1;i<a;++i) if(pf[i+a]) Add(i,a+C); Add(S,a),Add(a+C,T); ret=Dinic(); if(a-ret==N) { Pre(); ans=sum=0; for(int i=1;i<=a;++i) if(p[i]) { now[++sum].clear(); now[sum].push_back(u=i); do { v=u,u=p[u]-C; now[sum].push_back(u); p[v]=0; }while(p[u]); ans+=now[sum].size(); } } else if(a-ret==N+1) break; } printf("%d\n",ans); for(int i=1;i<=sum;++i) { printf("%d",now[i][0]); for(int j=1;j<now[i].size();++j) printf(" %d",now[i][j]); putchar(10); } return 0;}
阅读全文
0 0
- 【网络流24题】魔术球(最小路径覆盖+枚举)
- [网络流24题]魔术球问题 贪心||枚举答案+最小路径覆盖
- 线性规划与网络流24题の4 魔术球问题(最小路径覆盖)
- loj6003「网络流 24 题」魔术球(最小路径覆盖/打表贪心)
- [网络流24题] 04 魔术球问题 (有向无环图最小路径覆盖, 最大流)
- 网络流24题之四 魔术球问题 最小路径覆盖
- [网络流24题]魔术球问题(简化版) 最小路径覆盖+二分答案 + 很快的最大流
- 【网络流二十四题 魔术球问题】【DAG 最小路径覆盖->最大流】【灵感】
- 线性规划与网络流24题の3 最小路径覆盖问题(最小路径覆盖)
- 网络流24题3最小路径覆盖问题(洛谷 P2764 最小路径覆盖问题)
- [网络流24题] 03 最小路径覆盖问题(有向无环图最小路径覆盖,网络最大流)
- loj6002「网络流 24 题」最小路径覆盖(最小路径覆盖+二分图最大匹配)
- loj6002网络流 24 题 最小路径覆盖 最大流
- [网络流24题 #3]最小路径覆盖问题
- [网络流24题] 最小路径覆盖问题
- kyeremal-网络流24题T3-最小路径覆盖问题
- 【二分匹配】 [网络流24题] 最小路径覆盖问题
- code vs [网络流24题]最小路径覆盖问题
- 使用R画Wilkinson图
- Java跳出循环-break和continue语句
- Invitation Cards HDU
- Django自定义filter和自定义simple_tag
- TSP问题,Lingo程序实例
- 【网络流24题】魔术球(最小路径覆盖+枚举)
- 在Ubuntu14.04中安装ROS Indigo
- 【多校训练】hdu 6178 Monkeys 贪心+dfs+读入挂模版
- 深入浅出信号与槽
- Socket通讯读取数据阻塞解决方案
- java.io.IOException: java.util.concurrent.ExecutionException: java.net.SocketException: Software cau
- mysql 主从复制
- C#基础-011 三目运算
- 【跟着imooc重学java】break与continue的区别