BZOJ3511 土地划分 题解&代码
Posted Rainbow6174
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3511 土地划分 题解&代码相关的知识,希望对你有一定的参考价值。
pkusc发现自己不会费用流233333于是两天速成费用流【然而这是一道最小割(最大流QwQ
题意:
给出n个点m条边,并设定:
点x在被划分至集合A时获得权值A[x],否则即被划分至集合B并获得权值B[x];
边(x,y)连接的x和y均属于集合A时获得权值ea,均属于集合B时获得权值eb,否则获得权值-ec。
题解:这题…反正我是没自己建出图来。
对于点x,从S(代表集合A)向x连容量为va的边,从x向T(代表集合B)连容量为vb的边。
对于边(x,y),从S向x和y分别连容量为ea/2的边,从x和y向T分别连容量为eb/2的边,然后x和y中间互相连两条容量为ea/2+eb/2+ec的边。
这样的话,图中最大流就是划分这个图的最小花费。
于是答案就是权值和减去最小割(最大流)
反正换我肯定做不出来orz还是智商受到了限制
/**************************************************************
Problem: 3511
User: Rainbow6174
Language: C++
Result: Accepted
Time:1612 ms
Memory:6744 kb
****************************************************************/
#include <cstdio>
#include<iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int maxn = 10005;
const int maxm = 40005;
const int maxq = 50005;
const int inf = 0x3f3f3f3f;
int n,m,v,head[maxn],cur[maxn],cnt,st,ed,deep[maxn],q[maxq];
LL ans;
struct edge{
int v,w,next;
} e[4*maxn+10*maxm];
void add(int u, int v, int w,int rw)
{
e[cnt]=(edge){v,w,head[u]};
head[u]=cnt++;
e[cnt]=(edge){u,rw,head[v]};
head[v]=cnt++;
}
bool bfs(void)
{
for(int i=st; i<=ed; i++)
deep[i]=-1;
int h=0,t=0;
deep[st]=1;
q[t++]=st;
while(h != t)
{
int u = q[h++];
for(int i=head[u]; i!=-1; i=e[i].next)
if(e[i].w && deep[e[i].v]==-1)
{
deep[e[i].v]=deep[u]+1;
if(e[i].v==ed) return true;
q[t++]=e[i].v;
}
}
return false;
}
int dfs(int x,int flow)
{
if(x==ed)return flow;
int left=flow;
for(int i=cur[x]; i!=-1; i=e[i].next)
if(e[i].w && deep[e[i].v]==deep[x]+1)
{
int tmp=dfs(e[i].v,min(left,e[i].w));
left-=tmp;
e[i].w-=tmp;
e[i^1].w+=tmp;
if(e[i].w)cur[x]=i;
if(!left)return flow;
}
if(left==flow)deep[x]=-1;
return flow-left;
}
LL dinic(void)
{
LL ret=0;
while(bfs())
{
for(int i=st; i<=ed; i++)
cur[i]=head[i];
ret+=(LL)dfs(st,inf);
}
return ret;
}
int main(void)
{
scanf("%d%d",&n,&m);
st=0;ed=n+1;
for(int i=st; i<=ed; i++)
head[i]=-1;
add(st,1,inf,0);
add(n,ed,inf,0);
for(int i=2; i<n; i++)
{
scanf("%d",&v);v*=2;
add(st,i,v,0);
ans+=v;
}
for(int i=2; i<n; i++)
{
scanf("%d",&v);v*=2;
add(i,ed,v,0);
ans+=v;
}
for(int i=1; i<=m; i++)
{
int x,y,ea,eb,ec;
scanf("%d%d",&x,&y);
scanf("%d%d%d",&ea,&eb,&ec);
add(st,x,ea,0);
add(st,y,ea,0);
add(x,ed,eb,0);
add(y,ed,eb,0);
add(x,y,ea+eb+ec*2,ea+eb+ec*2);
ans+=(ea+eb)*2;
}
ans-=dinic();
printf("%lld\n",ans/2);
return 0;
}
以上是关于BZOJ3511 土地划分 题解&代码的主要内容,如果未能解决你的问题,请参考以下文章