您的位置:首页 > 其它

【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;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: