洛谷 P2765 魔术球问题(网络流24题-最大流)

题意:中文题(lrj黑书上好像有这道题)

思路:这个题的建图还真的是挺有意思的,我们把一个球拆成2个点a,b。 然后让a点连S点,b点连T点,如果有两个数的加和为平方数,那我们就用第一个数的a点连向第二个数的b点,这样就有一条流直接流向汇点T

代码:(顺便get了怎么打印路径,赋学习传送门

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

struct Edge{
    int next,to,f;
};
struct Dinic
{
    int s,t;
    Edge e[1000010];
    int cnt=2,head[1000010]={0};
    int dis[1000010]={0};
    Dinic (){}
    void init(int _s,int _t)
    {
        cnt=2;
        s=_s,t=_t;
        memset(head,0,sizeof(head));
    }
    void addedge(int u,int v,int f)
    {
        e[cnt]={head[u],v,f};
        head[u]=cnt++;
        e[cnt]={head[v],u,0};
        head[v]=cnt++;
    }
    bool bfs()
    {
        memset(dis,0,sizeof(dis));
        dis[s]=1;
        queue<int> q;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=head[u];i;i=e[i].next)
            {
                int v=e[i].to;
                if(!dis[v]&&e[i].f>0)
                {
                    dis[v]=dis[u]+1;
                    q.push(v);
                }
            }
        }
        return dis[t]!=0;
    }

    int dfs(int u,int flow)
    {
        if(u==t||flow==0) return flow;
        int flow_sum=0;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to,f=e[i].f;
            if(dis[v]!=dis[u]+1||f==0) continue;
            int temp=dfs(v,min(flow-flow_sum,f));
            e[i].f-=temp;
            e[i^1].f+=temp;
            flow_sum+=temp;
            if(flow_sum>=flow) break;
        }
        if(!flow_sum) dis[u]=-1;
        return flow_sum;
    }

    int maxflow()
    {
        int ans=0;
        while(bfs())
        {
            while(int temp=dfs(s,0x7fffffff))
                ans+=temp;
        }
        return ans;
    }
}DC;

int vis[20050];
int main()
{
    int n=read();
    int ball;
    int cnt=0;
    int s=0,t=20000;
    DC.init(s,t);
    for(cnt=0,ball=1;cnt<=n;cnt++){
        if(cnt){
            ball++;
        }
        for(;;ball++){
            DC.addedge(s,ball,1);
            DC.addedge(ball+10000,t,1);
            for(int i=1;i<ball;i++){
                if(sqrt(ball+i)==(int)sqrt(ball+i)){
                    DC.addedge(i,ball+10000,1);
                }
            }
            int as=DC.maxflow();
            if(!as)break;
        }
    }
    printf("%d",ball-1);
    for(int i=1;i<=ball-1;i++){
        if(vis[i])continue;
        vis[i]=true;cout<<endl<<i<<' ';
        int k=i;
        while(true){
            bool ok=false;
            for(int i=DC.head[k];i;i=DC.e[i].next){
                int v=DC.e[i].to,f=DC.e[i].f;
                if(v>10000&&f==0){
                    cout<<v-10000<<' ';
                    vis[v-10000]=true;
                    k=v-10000;ok=true;
                    break;
                }
            }
            if(!ok)break;
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lalalatianlalu/p/9809995.html
今日推荐