【codevs1234】魔术球问题

来源:互联网 发布:前锦网络南京地址 编辑:程序博客网 时间:2024/05/19 13:20

好题!一开始没想到,看了题解之后发现其实这样的增广方法以前是见过的,每次增加一个结点,然后跑最大流看是否能继续增广,直到不能增广为止,我记得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[N],matching[N],p[N],can[N],cur[N],head[N],d[N],num[N];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)            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;        }    }}
0 0
原创粉丝点击