您的位置:首页 > 其它

bzoj 3158 千钧一发(最小割)

2015-12-26 14:25 411 查看

3158: 千钧一发

Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 767 Solved: 290
[Submit][Status][Discuss]

Description



Input

第一行一个正整数N。

第二行共包括N个正整数,第 个正整数表示Ai。

第三行共包括N个正整数,第 个正整数表示Bi。

Output

共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值。

Sample Input

4

3 4 5 12

9 8 30 9

Sample Output

39

HINT

1<=N<=1000,1<=Ai,Bi<=10^6

Source

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: