[BZOJ3275]Number(最小割)
2016-04-06 08:24
519 查看
题目描述
传送门题解
很好想的最小割将每个ai拆成xi,yi
s->xi,ai
yi->t,ai
对于不能同时选的两个点,xi->yi,INF
乱搞了一下很开心地A掉了,看hzwer的题解跟我差不多更开心了。。。
然而reflash说我做的不对?
网上有一种奇偶的方法?
会了补上。。。
代码
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<cmath> using namespace std; const int max_n=3005; const int max_N=max_n*2+2; const int max_m=max_n*1000; const int max_e=max_m*2; const int INF=1e9; int n,a[max_n],N,sum,maxflow; int tot,point[max_N],next[max_e],v[max_e],remain[max_e]; int deep[max_N],cur[max_N]; queue <int> q; inline int in(){ int x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } inline int gcd(int a,int b){ if (!b) return a; else return gcd(b,a%b); } inline bool check(int a,int b){ if (gcd(a,b)!=1) return false; int c=a*a+b*b; int t=sqrt(c); if (t*t!=c) return false; return true; } 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 bool bfs(int s,int t){ for (int i=1;i<=N;++i) deep[i]=INF+1; deep[s]=0; for (int i=1;i<=N;++i) cur[i]=point[i]; while (!q.empty()) q.pop(); q.push(s); while (!q.empty()){ int now=q.front(); q.pop(); for (int i=point[now];i!=-1;i=next[i]) if (deep[v[i]]>INF&&remain[i]){ deep[v[i]]=deep[now]+1; q.push(v[i]); } } return deep[t]<INF; } inline int dfs(int now,int t,int limit){ if (now==t||!limit) return limit; int flow=0,f; for (int i=cur[now];i!=-1;i=next[i]){ cur[now]=i; if (deep[v[i]]==deep[now]+1&&(f=dfs(v[i],t,min(remain[i],limit)))){ flow+=f; limit-=f; remain[i]-=f; remain[i^1]+=f; if (!limit) break; } } return flow; } inline void dinic(int s,int t){ while (bfs(s,t)) maxflow+=dfs(s,t,INF); } int main(){ tot=-1; memset(point,-1,sizeof(point)); memset(next,-1,sizeof(next)); n=in(); for (int i=1;i<=n;++i) a[i]=in(),sum+=a[i]; N=n*2+2; for (int i=1;i<=n;++i) addedge(1,1+i,a[i]),addedge(1+n+i,N,a[i]); for (int i=1;i<n;++i) for (int j=i+1;j<=n;++j){ if (check(a[i],a[j])){ addedge(1+i,1+n+j,INF); addedge(1+j,1+n+i,INF); } } dinic(1,N); printf("%d\n",sum-(maxflow>>1)); }
总结
刚开始好像炸了int因为sum求的是和的两倍,求一倍的话似乎更方便而且不容易出错。
相关文章推荐
- Android 之 内存管理
- 把一个控件移除并不会马上销毁
- 【BZOJ1696】[Usaco2007 Feb]Building A New Barn新牛舍【中位数】【绝对值不等式】【贪心】
- viewpager加圆点应用
- leetcode:Move Zeros
- Visual Studio命令行创建库文件lib
- 获取某个类下的导航条
- 监听按钮的按下和抬起,,toucheBegin会和按钮的监听事件冲突
- LinkedList基本用法
- Asp.Net 动态生成验证码
- 控件从xib加载,默认尺寸跟xib一样大
- Android 之 zygote 与进程创建
- ASP.NET 防盗链源码
- 动态规划应用之一
- 链表-Merge Two Sorted Lists(合并两个单项链表)
- 去掉系统对我们图片的渲染
- initialize和Load方法
- .NET自动字符编码识别程序库 NChardet
- ios开发尺寸大全
- .NET写的过程中总结的正则表达式