【codevs1234】魔术球问题
2017-02-27 21:35
267 查看
好题!一开始没想到,看了题解之后发现其实这样的增广方法以前是见过的,每次增加一个结点,然后跑最大流看是否能继续增广,直到不能增广为止,我记得POJ2391也是这样的增广方法,不过那个是二分答案每次重新建图求最大流.
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int N=10010,inf=0x3f3f3f3f; int m,n,te,sz,s,t; int vis ,matching ,p ,can ,cur ,head ,d ,num ; struct edge{ int u,v,cap,flow,next; }e[100010]; queue<int>q; void add(int u,int v,int cap) { e[++te].u=u; e[te].v=v; e[te].flow=0; e[te].cap=cap; e[te].next=head[u]; head[u]=te; } void insert(int u,int v,int cap){add(u,v,cap),add(v,u,0);} int augment() { int a=inf,x=t; while(x!=s) { a=min(a,e[p[x]].cap-e[p[x]].flow); x=e[p[x]].u; } x=t; while(x!=s) { e[p[x]].flow+=a; e[p[x]^1].flow-=a; x=e[p[x]].u; } return a; } void bfs() { while(!q.empty())q.pop(); memset(d,0,sizeof(d)); q.push(t); while(!q.empty()) { int u=q.front(); for (int i=head[u];i;i=e[i].next) { int v=e[i].v; if (e[i].cap==0&&!d[v]) d[v]=d[u]+1,q.push(v); } q.pop(); } } int isap() { int flow=0,x=s; memset(num,0,sizeof(num)); copy(head,head+n+1,cur); bfs(); for (int i=1;i<=n;i++) ++num[d[i]]; while(d[s]<n) { if (x==t) { flow+=augment(); x=s; } int ok=0; for (int i=cur[x];i;i=e[i].next) { int v=e[i].v; if (e[i].cap>e[i].flow&&d[v]+1==d[x]) { p[v]=i; ok=1; cur[x]=i; x=v; break; } } if (!ok) { if (--num[d[x]]==0)break; int mx=n-1; for (int i=head[x];i;i=e[i].next) c97c if (e[i].cap>e[i].flow)mx=min(mx,d[e[i].v]); num[d[x]=mx+1]++; cur[x]=head[x]; if (x!=s)x=e[p[x]].u; } } return flow; } int main() { memset(vis,0,sizeof(vis)); memset(matching,-1,sizeof(matching)); int k=1;te=1; memset(can,0,sizeof(can)); for (int i=1;i*i<=4000;++i) can[i*i]=1; s=1,t=2;n=2; cin>>m; for (int i=0;i<=m;k++) { insert(s,n+1,1); insert(n+2,t,1); n+=2; for (int j=1;j<k;j++) if (can[k+j])insert((j<<1)+1,n,1); // for (int p=2;p<=te;p+=2) // cout<<e[p].u<<' '<<e[p].v<<' '<<e[p].cap<<endl; // getchar(); // cout<<isap()<<endl; if (!isap())i++; } n-=2;k-=2; for (int i=3;i<=n;i+=2) { for (int j=head[i];j;j=e[j].next) { int v=e[j].v-1>>1; if (e[j].flow==1) matching[i>>1]=v; } } cout<<k<<endl; for (int i=1;i<=k;i++) { int x=i; if (!vis[i]) { while(1) { vis[x]=1; printf("%d ",x); if (matching[x]==-1)break; else x=matching[x]; } cout<<endl; } } }
相关文章推荐
- 网络流24题4 魔术球问题 ssl 2604 code[vs] 1234
- CODE[VS]_1098 均分纸牌问题
- codevs (wikioi)1029遍历问题
- Code[VS] 1295 Nqueens N皇后问题
- CODE[VS] 1116 四色问题
- code vs 1029 遍历问题 区间dp
- VS部署中的ProductCode问题
- [CODEVS1216]跳马问题
- Code[VS] 1029 遍历问题
- Code[vs]1014 装箱问题
- CODE[VS] 1295 N皇后问题
- 遍历问题[CODEVS1029]解题报告
- codevs1014 装箱问题(DP)
- CODE[VS]1116 四色问题
- Code[VS] 3377 接水问题2
- CODE[VS]_1214 线段覆盖问题
- CODEVS_1033 蚯蚓的游戏问题 网络流 最小费用流 拆点
- codevs1282 约瑟夫问题
- CODE[VS] 1016 税收与补贴问题
- CODE[VS] 1295 N皇后问题