博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷P2765 魔术球问题(最大流)
阅读量:7114 次
发布时间:2019-06-28

本文共 2798 字,大约阅读时间需要 9 分钟。

 

%%%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
3 #include
4 #include
5 #include
6 #include
7 #include
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 num19 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
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 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9498668.html

你可能感兴趣的文章
Pillow实现图片对比
查看>>
Centos上安装 OpenNebula Management Console
查看>>
【Oracle】 RAC 环境删除oracle 之一
查看>>
android 通过重写ScrollView和Listview完成上下滑动选中不同位置标题的效果
查看>>
[华为机试练习题]34.识别有效的IP地址和掩码并进行分类统计
查看>>
简单选择排序
查看>>
SQL应用与开发:(四)视图的应用
查看>>
dbcp重连失败问题排查记录(timeout设置)
查看>>
Pay attention: Oracle INTEGER is NUMBER(p) not INT4 in PostgreSQL
查看>>
虚拟机linux系统能够上网但是不能ping主机
查看>>
Http 400 --- The request sent by the client was syntactically incorrect
查看>>
关于char**与const char**
查看>>
Linux之同步机制(信号量,自旋锁)
查看>>
nginx内部锁的实现
查看>>
二分查找法
查看>>
硬解码播放器上如何实现截GIF功能?
查看>>
[译] 使用 Kotlin 协程改进应用性能
查看>>
初识URLSeesion
查看>>
两步实现安卓手机秒变网络摄像头
查看>>
Travis-CI自动化测试并部署至自己的CentOS服务器
查看>>