[网络流24题][COGS396]魔术球问题简化版(最小割)
2016-03-19 20:24
681 查看
题目描述
传送门注意题目描述:保证答案小于2000并非1600!
题解
有向无环图的最小路径覆盖问题,转化成最小割问题。最小路径覆盖数随球的数量递增不递减,满足单调性,所以可以枚举答案(或二分答案),对于特定的答案求出最小路径覆盖数,一个可行解就是最小路径覆盖数等于N的答案,求出最大的可行解就是最优解。本问题更适合枚举答案而不是二分答案,因为如果顺序枚举答案,每次只需要在残量网络上增加新的节点和边,再增广一次即可。如果二分答案,就需要每次重新建图,大大增加了时间复杂度。
具体方法可以顺序枚举A的值,当最小路径覆盖数刚好大于N时终止,A-1就是最优解。
代码
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int max_n=4000; const int max_N=max_n*2+2; const int max_m=max_n*max_n*2; const int max_e=max_m*2; const int INF=1e9; int n,N,maxflow,ans; bool can[max_n]; int tot,point[max_N],next[max_e],v[max_e],remain[max_e]; int deep[max_N],last[max_N],cur[max_N],num[max_N]; queue <int> q; inline void addedge(int x,int y,int cap){ ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cap; ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; } inline void bfs(int t){ while (!q.empty()) q.pop(); q.push(t); while (!q.empty()){ int now=q.front(); q.pop(); for (int i=point[now];i!=-1;i=next[i]) if (deep[v[i]]==max_N&&remain[i^1]){ deep[v[i]]=deep[now]+1; q.push(v[i]); } } } inline int addflow(int s,int t){ int ans=INF,now=t; while (now!=s){ ans=min(ans,remain[last[now]]); now=v[last[now]^1]; } now=t; while (now!=s){ remain[last[now]]-=ans; remain[last[now]^1]+=ans; now=v[last[now]^1]; } return ans; } inline void isap(int s,int t,int number){ bfs(t); for (int i=1;i<=number;++i) ++num[deep[i]]; int now=s; while (deep[s]<max_N){ if (now==t){ maxflow+=addflow(s,t); now=s; break; } bool has_find=false; for (int i=point[now];i!=-1;i=next[i]) if (deep[v[i]]+1==deep[now]&&remain[i]){ has_find=true; cur[now]=i; last[v[i]]=i; now=v[i]; break; } if (!has_find) break; } } int main(){ freopen("balla.in","r",stdin); freopen("balla.out","w",stdout); scanf("%d",&n); for (int i=1;i*i<=4000;++i) can[i*i]=true; tot=-1; memset(point,-1,sizeof(point)); memset(next,-1,sizeof(next)); for (int t=1;;++t){ addedge(1,2*t+1,1); addedge(2*t+2,2,1); for (int i=1;i<t;++i) if (can[i+t]) addedge(2*i+1,2*t+2,1); deep[2*t+1]=max_N; deep[2*t+2]=max_N; deep[1]=max_N; deep[2]=0; isap(1,2,t*2+2); ans=t-maxflow; if (ans>n){ printf("%d\n",t-1); break; } } return 0; }
总结
如何每次加边并进行一次增广注意一下。相关文章推荐
- [网络流24题][BZOJ1475]方格取数(最小割)
- JavaWeb开发之六:HttpServletRequest对象
- JavaWeb开发之五:HttpServletResponse对象
- JavaWeb开发之三:HTTP协议
- Linux网络基础-ISO/OSI七层模型、TCP/IP四层模型
- NTP 网络时间协议服务配置说明(Windows)
- 56.网络请求及各类错误代码含义总结(Errors Code)
- 简析TCP的三次握手与四次分手
- <%@ taglib prefix="c" uri="http://java.sun.com/jst
- https://github.com/MediaTek-Labs/linkit-smart-7688-webUI
- HttpURLConnection使用
- Connection to https://dl-ssl.google.com refused
- UNIX网络编程之旅-配置unp.h头文件环境
- 一点关于卷积神经网络(CNN)的想法
- 如何简单形象又有趣地讲解神经网络是什么?知乎
- HTTP Header 详解
- Android网络编程使用HttpClient访问web站点
- Netty精粹之TCP粘包拆包问题
- 问题:XMLHttpRequest cannot load file~~Origin 'null' is therefore not allowed access
- TCP TIME_WAIT分析