第七场春训,谢谢szh、zkj学长 qwq!
(补题式学习法)
【BUAA Spring Training 07】
Tags:最大流 费用流 可行流 二分图
Problem A. Petya and Graph
[A] 题意
一个子图是由原图边的子集和点的子集构成的图(每条边的端点必须是点子集中的点)
子图的权值总和定义为这个子图的边权和减去点权和。
给定一个没有自环重边的无向图,求最大子图权值。点数边数都 ∈ [ 1 , 1 0 3 ] \in [1, 10^3] ∈[1,103]
[A] 思路
看到这个范围就应该想到是网络流…
我们把每条边视为一个中介点,那么问题就转换为了典型的最大权闭合子图。
建图方式就是,原图每个结点以点权为容量连向超级汇,然后把每条边拆成一个中介点,从超级源拉一条容量为边权的弧过来,接着再把中介点和原边的两个端点以无穷容量连接就行了。
然后把原图边权全部相加,再减去建图后的最大流就是答案。
时间复杂度:网络流,你懂的, O ( O( O(能过 ) ) )。
[A] 代码
#include <cstdio>
#include <cstring>
#include <limits>
#define LL long long
#define ULL unsigned LL
#define _BS 1048576
char _bf[_BS];
char *__p1=_bf,*__p2=_bf;
#define _IO char *_p1=__p1,*_p2=__p2;
#define _OI __p1=_p1,__p2=_p2;
#ifdef _KEVIN
#define GC getchar()
#else
#define GC (_p1==_p2&&(_p2=(_p1=_bf)+fread(_bf,1,_BS,stdin),_p1==_p2)?EOF:*_p1++)
#endif
#define PC putchar
#define _Q_(x) {register char _c=GC,_v=1;for(x=0;_c<48||_c>57;_c=GC)if(_c==45)_v=-1;
#define _H_(x) for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=GC);if(_v==-1)x=-x;}
#define sc(x) _Q_(x)_H_(x)
#define se(x) _Q_(x)else if(_c==EOF)return 0;_H_(x)
#define _G1(_1) int _1;sc(_1)
#define _G2(_1,_2) int _1,_2;sc(_1)sc(_2)
#define _G3(_1,_2,_3) int _1,_2,_3;sc(_1)sc(_2)sc(_3)
#define _gG(_1,_2,_3,_get, ...) _get
#define get(...) _gG(__VA_ARGS__,_G3,_G2,_G1, ...)(__VA_ARGS__)
#define _F0N(i,n) for(auto i=0;i<(n);++i)
#define _FLR(i,l,r) for(auto i=(l);i<(r);++i)
#define _gF(_1, _2, _3, _F, ...) _F
#define F(...) _gF(__VA_ARGS__,_FLR,_F0N, ...)(__VA_ARGS__)
#define _FD0(i,n) for(auto i=0;i<=(n);++i)
#define _FDL(i,l,r) for(auto i=(l);i<=(r);++i)
#define _gFD(_1, _2, _3, _FD, ...) _FD
#define FD(...) _gFD(__VA_ARGS__,_FDL,_FD0, ...)(__VA_ARGS__)
#define FRC(R,C) for(int r=0;r<R;++r)for(int c=0;c<C;++c)
template<class T>
void UPRT(const T _){if(_>=10)UPRT(_/10);PC(_%10+48);}
#define UPL(_) UPRT(_),PC(10)
template<class T>
void PRT(const T _){if(_<0){PC(45),UPRT<ULL>(-(ULL)_);return;}if(_>=10)PRT(_/10);PC(_%10+48);}
#define PL(_) PRT(_),PC(10)
#define MAX(a, b) ((a)>(b)?(a):(b))
#define MIN(a, b) ((a)<(b)?(a):(b))
constexpr int MV(6e3+7), ME(MV<<1);
template <typename cint>
class Dinic
{
private:
static constexpr cint CINT_MAX = std::numeric_limits<cint>::max();
struct Ed
{
int ne, u, v;
cint c;
} ed[ME];
int head[MV], cur[MV], tot;
int V, S, T;
int de[MV];
bool bfs()
{
static int q[MV];
int hd = 0, tl = 0;
memset(de, 0, sizeof(*de) * (V+2));
de[q[tl++]=S] = 1;
while (hd != tl)
{
const int u = q[hd++];
for (int i=head[u]; i; i=ed[i].ne)
{
const int v = ed[i].v;
if (ed[i].c && !de[v])
{
de[q[tl++]=v] = de[u] + 1;
if (v == T)
return true;
}
}
}
return false;
}
cint dfs(const int u, cint in)
{
if (u == T)
return in;
cint out = 0;
for (int i=cur[u]; in&&(cur[u]=i); i=ed[i].ne)
{
if (ed[i].c>0 && de[ed[i].v]==de[u]+1)
{
const cint tp = dfs(ed[i].v, MIN(in, ed[i].c));
in -= tp, out += tp, ed[i].c -= tp, ed[i^1].c += tp;
}
}
if (in || !out)
de[u] = -1;
return out;
}
public:
void init(const int v)
{
if (V)
memset(head, 0, sizeof(*head) * (V+2));
V = v;
tot = 1;
}
void edd(const int u, const int v, const cint c = CINT_MAX)
{
ed[++tot].ne=head[u], ed[tot].u=u, ed[tot].v=v, ed[tot].c=c, head[u]=tot;
ed[++tot].ne=head[v], ed[tot].u=v, ed[tot].v=u, ed[tot].c=0, head[v]=tot;
}
cint max_flow(const int s, const int t)
{
cint sum = 0;
S = s, T = t;
while (bfs())
{
memcpy(cur, head, sizeof(*head) * (V+2));
sum += dfs(s, CINT_MAX);
}
return sum;
}
};
Dinic<LL> mf;
int main()
{
_IO
get(V, E);
const int S = 0, T = V+E+1;
mf.init(T-S+1);
FD(i, 1, V)
{
get(ai) // cost
mf.edd(i, T, ai);
}
LL sum = 0;
FD(i, 1, E)
{
get(u, v, c)
sum += c;
mf.edd(V+i, u);
mf.edd(V+i, v);
mf.edd(S, V+i, c);
}
PL(sum - mf.max_flow(S, T));
#ifdef _KEVIN
getchar();
#endif
return 0;
}
Problem B. Scaygerboss
(待更)