您的位置:首页 > 理论基础 > 计算机网络

BZOJ1391: [Ceoi2008]order 最大权闭合子图

2016-12-04 16:00 441 查看

题解:

转化成最大权闭合子图后求最小割,获得一个任务的价值的不同方式有三种:
1.不做这个任务 2.购买对应的机器 3.租借完成这个任务所需要的全部机器
在图中对应着三种割:
1.将n个任务向原点连边,权值为任务的利润;
2.将m个机器向汇点连边,权值为机器的价格;

3.将每个任务像对应的机器连边,权值为租借价格;

然后用所有任务价格之和减去最小割就是ans
(注意本题要用到当前弧优化)

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2505;
const int M=4000005;
const int inf=2e9;
int n,m,ans;
int lj
,nxt[M],to[M],w[M],pre
,cnt=1;
void add(int f,int t,int p)
{
cnt++,to[cnt]=t,nxt[cnt]=lj[f],lj[f]=cnt,w[cnt]=p;
cnt++,to[cnt]=f,nxt[cnt]=lj[t],lj[t]=cnt,w[cnt]=0;
}
int S,T,h=1,t,Q
,d
;
bool bfs()
{
memset(d,0,sizeof(d));
d[S]=1;
Q[++t]=S;
while(h!=t+1)
{
int x=Q[h];
if(++h==N) h=1;
for(int i=lj[x];i;i=nxt[i])
if(w[i]&&!d[to[i]])
{
d[to[i]]=d[x]+1;
if(++t==N) t=1;
Q[t]=to[i];
}
}
if(d[T]) return true;
return false;
}
int dfs(int x,int v)
{
if(x==T||v==0) return v;
int ret=0;
for(int i=pre[x];i;i=nxt[i])
if(w[i]&&d[to[i]]==d[x]+1)
{
int f=dfs(to[i],min(w[i],v));
w[i]-=f;
if(w[i]) pre[x]=i;
w[i^1]+=f;
v-=f;
ret+=f;
if(v==0) break;
}
if(ret==0) d[x]=-1;
return ret;
}
void Build()
{
int x,a,b;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&a);
add(S,i,x);
ans+=x;
for(int j=1;j<=a;j++)
{
scanf("%d%d",&x,&b);
add(i,n+x,b);
}
}
T=n+m+1;
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
add(i+n,T,x);
}
}
int main()
{
scanf("%d%d",&n,&m);
Build();
while(bfs())
{
for(int i=S;i<=T;i++) pre[i]=lj[i];
ans-=dfs(S,inf);
}
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息