bzoj 3158 千钧一发(最小割)
2015-12-26 14:25
411 查看
3158: 千钧一发
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 767 Solved: 290
[Submit][Status][Discuss]
Description
Input
第一行一个正整数N。第二行共包括N个正整数,第 个正整数表示Ai。
第三行共包括N个正整数,第 个正整数表示Bi。
Output
共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值。Sample Input
43 4 5 12
9 8 30 9
Sample Output
39HINT
1<=N<=1000,1<=Ai,Bi<=10^6Source
Katharon+#1【思路】
最小割。
注意到ai,aj同时是偶数或同时是奇数时必定可以被同时选出:
1 同为偶数满足条件2
2 同为奇数时有(2a+1)^2+(2b+1)^2=2(2a^2+2b^2+2a+2b+1),所以满足条件1。
以此构二分图,设奇数为X结点偶数为Y结点,如果不满足任一条件则连边(Xi,Yj,INF),同时相应连S到X,Y到T的边容量为b,那么答案就是一个二分图最小割,即通过删除一些结点使得满足剩下的结点不相邻且有b之和最小。
【代码】
#include<cstdio> #include<cmath> #include<queue> #include<cstring> #include<iostream> using namespace std; typedef long long LL; const int maxn = 4000+10; const int INF = 1e9+1e9; struct Edge{ int u,v,cap,flow; }; struct Dinic { int n,m,s,t; int d[maxn],cur[maxn],vis[maxn]; vector<int> G[maxn]; vector<Edge> es; void init(int n) { this->n=n; for(int i=0;i<n;i++) G[i].clear(); es.clear(); } void AddEdge(int u,int v,int cap) { es.push_back((Edge){u,v,cap,0}); es.push_back((Edge){v,u,0,0}); m=es.size(); G[u].push_back(m-2); G[v].push_back(m-1); } bool bfs() { queue<int> q; memset(vis,0,sizeof(vis)); vis[s]=1; d[s]=0; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<G[u].size();i++) { Edge &e=es[G[u][i]]; int v=e.v; if(!vis[v] && e.cap>e.flow) { vis[v]=1; d[v]=d[u]+1; q.push(v); } } } return vis[t]; } int dfs(int u,int a) { if(u==t || a==0) return a; int f,flow=0; for(int& i=cur[u];i<G[u].size();i++) { Edge& e=es[G[u][i]]; int v=e.v; if(d[v]==d[u]+1 && (f=dfs(v,min(a,e.cap-e.flow)))>0) { e.flow+=f; es[G[u][i]^1].flow-=f; flow+=f , a-=f; if(!a) break; } } return flow; } int maxflow(int s,int t) { this->s=s , this->t=t; int flow=0; while(bfs()) { memset(cur,0,sizeof(cur)); flow+=dfs(s,INF); } return flow; } } dc; int n; int a[maxn],b[maxn]; bool issqr(LL x) { return sqrt(x)*sqrt(x) == x; } int gcd(int x,int y) { return y==0? x:gcd(y,x%y); } bool jud(LL x,LL y) { LL t=x*x+y*y , sq=sqrt(t); if(sq*sq!=t) return 1; if(gcd(x,y)>1) return 1; return 0; } int main() { scanf("%d",&n); dc.init(n+2); int s=n,t=s+1; int ans=0; for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<n;i++) scanf("%d",&b[i]) , ans+=b[i]; for(int i=0;i<n;i++) if((a[i]&1)) dc.AddEdge(s,i,b[i]); else dc.AddEdge(i,t,b[i]); for(int i=0;i<n;i++) for(int j=0;j<n;j++) if((a[i]&1) && (a[j]&1)==0) if(!jud(a[i],a[j])) dc.AddEdge(i,j,INF); ans-=dc.maxflow(s,t); printf("%d",ans); return 0; }
相关文章推荐
- 1-5-03:求整数的和与均值
- 为RecyclerView添加头视图和尾视图
- ubuntu 15.04 编译安装 mysql 5.5.44
- JavaScript原型、函数伪装(apply,call)、继承
- 点击按钮图片放大查看
- java的静态导入
- Mysql入门实战上
- python threading 模块来实现多线程
- Objective - C - 字面量(Literals)整理
- OpenGL&CG技术之Render To Texture
- 设计模式之观察者模式
- 相机开发(聚焦、横竖屏拍照、照片存储、连续拍照等)
- KMP算法
- React-Native 组件练习-购物app侧滑菜单
- 数据库系统概论复习总结2 --- 第二章关系数据库
- Java基础--反射
- [LeetCode]Scramble String
- C语言简易的硬盘操作器
- linux查看历史命令history
- HTML5开头声明