卧薪尝胆,厚积薄发。
土地划分
Date: Thu Sep 13 20:47:49 CST 2018
In Category:
NoCategory
Description:
给一个图,
$1$
属于
$A$
集合,
$2$
属于
$B$
集合,每个点在
$A$
或
$B$
有不同的价值
$VA,VB$
,每条边如果两个点都在
$A$
或
$B$
有不同的加成
$EA,EB$
,如果分别在不同集合有扣分
$EC$
。
$1\le n \le 10000$
Solution:
同小
$M$
的作物,每个点从原点向这个点连在
$VA$
,向汇点连
$VB$
,对于每条边
$(u,v)$
新建两个点
$X,Y$
,连边
$S\xrightarrow{EA} X$
,
$X\xrightarrow {INF}u$
,
$X\xrightarrow {INF}v$
,
$u\xrightarrow {INF}Y$
,
$v\xrightarrow {INF}Y$
,
$Y\xrightarrow {INF}T$
,
$u\xleftarrow {EC}v$
,
$u\xrightarrow {EC}v$
然后跑最小割,用
$\begin{align}\sum VA+\sum VB+\sum EA+\sum EB-\end{align}$
最小割就行了。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
inline int read()
{
register int res = 0;
register char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res;
}
int n,m;
#define MAXN 10010
#define MAXM 40010
int vala[MAXN],valb[MAXN];
#define INF 0x3f3f3f3f
int s,t;
struct edge
{
int to,nxt,f;
}e[MAXN * 2 * 2 + MAXM * 8 * 2];
int edgenum = 0;
int lin[MAXN + MAXM * 2];
inline void add(int a,int b,int f)
{
e[edgenum].to = b;e[edgenum].f = f;e[edgenum].nxt = lin[a];lin[a] = edgenum;++edgenum;
e[edgenum].to = a;e[edgenum].f = 0;e[edgenum].nxt = lin[b];lin[b] = edgenum;++edgenum;
return;
}
int ch[MAXN + MAXM * 2];
inline bool BFS()
{
queue<int> q;q.push(s);
memset(ch,-1,sizeof(ch));ch[s] = 0;
while(!q.empty())
{
register int k = q.front();q.pop();
for(register int i = lin[k];i != -1;i = e[i].nxt)
{
if(ch[e[i].to] == -1 && e[i].f)
{
ch[e[i].to] = ch[k] + 1;
q.push(e[i].to);
}
}
}
return (ch[t] != -1);
}
int flow(int k,int f)
{
if(k == t)return f;
register int r = 0;
for(register int i = lin[k];i != -1 && f > r;i = e[i].nxt)
{
if(ch[e[i].to] == ch[k] + 1 && e[i].f)
{
register int l = flow(e[i].to,min(f - r,e[i].f));
e[i].f -= l;r += l;e[i ^ 1].f += l;
}
}
if(r == 0)ch[k] = -1;
return r;
}
inline int dinic()
{
register int ans = 0,r;
while(BFS())while(r = flow(s,INF))ans += r;
return ans;
}
int main()
{
memset(lin,-1,sizeof(lin));
n = read();m = read();
for(register int i = 2;i <= n - 1;++i)vala[i] = read();vala[1] = INF;vala[n] = 0;
for(register int i = 2;i <= n - 1;++i)valb[i] = read();valb[1] = 0;valb[n] = INF;
s = n + 2 * m + 1;t = s + 1;
register int ans = 0;
for(register int i = 1;i <= n;++i)
{
add(s,i,vala[i]);
add(i,t,valb[i]);
if(i != 1 && i != n)ans += vala[i] + valb[i];
}
register int x,y,a,b,c;
for(register int i = 1;i <= m;++i)
{
x = read();y = read();a = read();b = read();c = read();
ans += a + b;
add(s,n + i * 2 - 1,a);add(n + i * 2,t,b);
add(n + i * 2 - 1,x,INF);add(n + i * 2 - 1,y,INF);
add(x,n + i * 2,INF);add(y,n + i * 2,INF);
add(x,y,c);add(y,x,c);
}
cout << ans - dinic() << endl;
return 0;
}
Another Solution:
二元关系最小割模型。
首先列出方程:
如果
$x$
和
$y$
都在
$S$
:价值为
$VA_x+VA_y+EA_{x,y}$
,割掉了边
$x\to T,y\to T$
即
$VA_x+VA_y+VB_x+VB_y+EA_{x,y}+EB_{x,y}-c-d=VA_x+VA_y+EA_{x,y}$
那么
$VB_x+VB_y+EB_{x,y}=c+d$
如果
$x$
和
$y$
都在
$T$
:价值为
$VB_x+VB_y+EB_{x,y}$
,割掉了边
$S\to x,S\to y$
即
$VA_x+VA_y+VB_x+VB_y+EA_{x,y}+EB_{x,y}-a-b=VB_x+VB_y+EB_{x,y}$
那么
$VA_x+VA_y+EA_{x,y}=a+b$
如果
$x$
在
$S$
,
$y$
在
$T$
:价值为
$VA_x+VB_y-EC_{x,y}$
,割掉边
$S\to y,x\to y,x\to T$
即
$VA_x+VA_y+VB_x+VB_y+EA_{x,y}+EB_{x,y}-b-e-c=VA_x+VB_y-EC_{x,y}$
那么
$VA_y+VB_x+EA_{x,y}+EB_{x,y}+EC_{x,y}=b+e+c$
如果
$x$
在
$T$
,
$y$
在
$S$
:价值为
$VB_x+VA_y-EC_{x,y}$
,割掉边
$S\to x,y\to x,x\to T$
即
$VA_x+VA_y+VB_x+VB_y+EA_{x,y}+EB_{x,y}-a-f-d=VB_x+VA_y-EC_{x,y}$
那么
$VA_x+VB_y+EA_{x,y}+EB_{x,y}+EC_{x,y}=a+f+d$
这个方程有无穷多组解,然而由于
$x$
和
$y$
对称,所以结出来的结果是:
$a=VA_x+\frac 1 2EA_{x,y},b=VA_y+\frac 1 2 EA_{x,y}$
$c=VB_x+\frac 1 2EB_{x,y},d=VB_y+\frac 1 2 EB_{x,y}$
$e=f=\frac 1 2 EA_{x,y}+\frac 1 2EB_{x,y}+EC_{x,y}$
按这个把边权放大
$2$
倍建图即可。
没有代码。
In tag:
图论-dinic
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡