zoukankan      html  css  js  c++  java
  • 洛谷P2765 魔术球问题(最大流)

    传送门

    %%%KSkun大佬

    话说明明是网络流……这题竟然还有打表找规律和纯贪心AC的……都是神犇啊……

    来说一下如何建图。首先把每一个点拆成$X_i$和$Y_i$,然后$S$向$X_i$连一条容量为$1$的边,$Y_i$向$T$连一条容量为$1$的边。对于能和它组成完全平方数的点,从$A_j$向$B_i$连一条容量为$1$的边

    然后考虑一下,加球不会导致柱子减少,所以可以枚举球数,然后每次加一个球,并跑一次最大流。如果新加入的球是能加到某一个柱子中的,那么这一次跑最大流是能得到新流的,只要能一直得到新流就一直加,当不能的时候,将柱子数加一(即将这一个球放到新的柱子上)

    当柱子数等于$n+1$的时候退出,因为第$n+1$根柱子是刚被加的,所以在放最后一个球之前,所有的球都能放在$n$根柱子中,那么当前的球数减一就是答案

    然后考虑一下怎么求方案。对于每一个点,我们可以定义$X_i=i*2,Y_i=i*2+1$,那么可以保证任意两个点的$X_i$和$Y_i$不会重复,且不管在哪一个点,除以二之后就是原来的点。那么我们可以在跑$dfs$的时候,把每一个可以往下走增广路的点连边(这就说明他们相加是完全平方数,可以放在同一个柱子里),那么就可以形成一个类似链表的东西。记录一下每一根柱子一开始放的球,然后沿着链表去找这个柱子上有哪些球就可以了

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<queue>
     7 #include<cmath>
     8 using namespace std;
     9 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    10 char buf[1<<21],*p1=buf,*p2=buf;
    11 inline int read(){
    12     #define num ch-'0'
    13     char ch;bool flag=0;int res;
    14     while(!isdigit(ch=getc()))
    15     (ch=='-')&&(flag=true);
    16     for(res=num;isdigit(ch=getc());res=res*10+num);
    17     (flag)&&(res=-res);
    18     #undef num
    19     return res;
    20 }
    21 char sr[1<<21],z[20];int C=-1,Z;
    22 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    23 inline void print(int x){
    24     if(C>1<<20)Ot();
    25     while(z[++Z]=x%10+48,x/=10);
    26     while(sr[++C]=z[Z],--Z);
    27 }
    28 const int inf=0x3f3f3f3f,N=100005,M=400005;
    29 int head[N],Next[M],ver[M],edge[M],tot=1,Pre[N];
    30 inline void add(int u,int v,int e){
    31     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
    32     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0;
    33 }
    34 int dep[N],s,t;
    35 int n,m,cnt;
    36 queue<int> q;
    37 bool bfs(){
    38     memset(dep,-1,sizeof(dep));
    39     dep[s]=0,q.push(s);
    40     while(!q.empty()){
    41         int u=q.front();q.pop();
    42         for(int i=head[u];i;i=Next[i]){
    43             int v=ver[i];
    44             if(dep[v]<0&&edge[i])
    45             dep[v]=dep[u]+1,q.push(v);
    46         }
    47     }
    48     return ~dep[t];
    49 }
    50 int dfs(int u,int limit){
    51     if(!limit||u==t) return limit;
    52     int flow=0,f;
    53     for(int i=head[u];i;i=Next[i]){
    54         int v=ver[i];
    55         if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){
    56             flow+=f,limit-=f;
    57             edge[i]-=f,edge[i^1]+=f;
    58             Pre[u>>1]=v>>1;
    59             if(!limit) break;
    60         }
    61     }
    62     return flow;
    63 }
    64 int dinic(){
    65     int flow=0;
    66     while(bfs()) flow+=dfs(s,inf);
    67     return flow;
    68 }
    69 bool vis[N];int w[65];
    70 int main(){
    71     n=read();
    72     s=0,t=10005;
    73     while(m<=n){
    74         ++cnt;
    75         add(s,cnt<<1,1),add(cnt<<1|1,t,1);
    76         for(int i=sqrt(cnt)+1;i*i<(cnt<<1);++i) add((i*i-cnt)<<1,cnt<<1|1,1);
    77         int s=dinic();
    78         if(!s) w[++m]=cnt;
    79     }
    80     print(--cnt),sr[++C]=10;
    81     for(int i=1;i<=n;++i){
    82         int u=w[i];
    83         if(!vis[u]){
    84             print(u),sr[++C]=32,vis[u]=1;
    85             while(Pre[u]&&Pre[u]!=t>>1){
    86                 u=Pre[u];
    87                 vis[u]=1;
    88                 print(u),sr[++C]=32;
    89             }
    90             sr[++C]=10;
    91         }
    92     }
    93     Ot();
    94     return 0;
    95 }
  • 相关阅读:
    关于gulp的压缩js和css
    关于vant的定制主题问题
    关于jquery-Validate
    关于bootstrap-table插件的问题
    Windows下sass无法编译
    Hibernate基础知识整理(三)
    Hibernate基础知识整理(二)
    Hibernate基础知识整理(一)
    学习Hibernate之Eclipse安装hibernate tools插件
    JDBC连接池的cvalidationQuery设置 (参考)
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9498668.html
Copyright © 2011-2022 走看看