我写的第一道最小割¿¿¿
二选一,考虑一个鱼刺型建图(自己编的名字),然后用最小割求最小花费。
鱼刺性建图大概就是,中间有一排点,然后位于左侧的 连向这一排点,这一排点连向右侧的 ,看起来就很像鱼刺(?)
trick:最大价值=总价值-最小花费
如果这个位置是 ,那么源点 连到它一条流量为 的边,若存在则代表选 ,若割掉则代表花费了 的代价选为 ;如果这个位置是 ,那么它连到汇点 一条流量为 的边,若存在则代表选 ,若割掉则代表花费了 的代价选为 .
首先这个 是没有用的,就如果当二五仔要赔钱的话,把 加上 ,然后最后总答案再减去 即可。
现在这个限制是:如果这些位置你都选 ,就可以喜提 的价值。对应到最小割上:先假定满足条件,获得 的价值;如果这些位置的 点与 边有一条没被割掉,那么就需要付出 的代价。
那么建一个新点 ,如果它限制的位置都选 ,就连 ,,也就是 在二分图中和 点位于一部分。如果它限制的位置都选 也同理,只不过它在二分图中和 点位于一部分。
感性理解一下为什么这样子的最小割是最小花费:假设它限制若干位置都选 ,如果某些位置本来填的是 ,那么如果那个位置连向 的边没有被割掉,不符合限制, 一定要被割掉,符合题意;如果某些位置本来填的是 ,如果这个位置 对应的边被割掉了,在最小割中,那么从它开始一定至少可以到达一个没有被割掉的限制 ,这样流可以从 流过,在这一路中,只有 的边是可以割的(若割掉所有的 ,那么 一定不会割掉,因为割掉的话就不优了),所以 一定要割掉,符合题意。
至于可能出现 流量的边,其实是无关紧要的(?)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#define pb emplace_back
#define mp std::make_pair
#define fi first
#define se second
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef std::vector<int> vi;
const ll mod = 998244353;
ll Add(ll x, ll y) { return (x+y>=mod) ? (x+y-mod) : (x+y); }
ll Mul(ll x, ll y) { return x * y % mod; }
ll Mod(ll x) { return x < 0 ? (x + mod) : (x >= mod ? (x-mod) : x); }
ll cadd(ll &x, ll y) { return x = (x+y>=mod) ? (x+y-mod) : (x+y); }
ll cmul(ll &x, ll y) { return x = x * y % mod; }
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template<typename T, typename... T2> T Max(T x, T2 ...y) { return Max(x, y...); }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template<typename T, typename... T2> T Min(T x, T2 ...y) { return Min(x, y...); }
template <typename T> T cmax(T &x, T y) { return x = x > y ? x : y; }
template <typename T> T cmin(T &x, T y) { return x = x < y ? x : y; }
template <typename T>
T &read(T &r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
template<typename T1, typename... T2>
void read(T1 &x, T2& ...y) { read(x); read(y...); }
const int N = 100010;
const int M = 500010;
const ll INF = 0x7fffffffffffffff;
int n, m, g;
int a[N], v[N];
int tot, S, T, ent = 1, head[N], cur[N], dis[N];
struct Edge {
int to, nxt;
ll fl;
}e[M << 1];
inline void add(int x, int y, ll z) {
//printf("%d %d %d\n", x, y, z);
e[++ent].to = y; e[ent].fl = z; e[ent].nxt = head[x]; head[x] = ent;
e[++ent].to = x; e[ent].fl = 0; e[ent].nxt = head[y]; head[y] = ent;
}
bool bfs() {
for(int i = 1; i <= tot; ++i) dis[i] = -1, cur[i] = head[i];
std::queue<int>q;
q.push(S); dis[S] = 0;
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = head[x]; i; i = e[i].nxt) {
int v = e[i].to;
if(dis[v] == -1 && e[i].fl) {
dis[v] = dis[x] + 1;
q.push(v);
}
}
}
return dis[T] != -1;
}
ll dfs(int x, ll lim) {
if(x == T) return lim;
ll flow = 0;
for(int i = cur[x]; i && flow < lim; i = e[i].nxt) {
int v = e[i].to; cur[x] = i;
if(dis[v] == dis[x] + 1 && e[i].fl) {
ll f = dfs(v, Min(e[i].fl, lim - flow));
flow += f; e[i].fl -= f; e[i^1].fl += f;
}
}
return flow;
}
ll dinic() {
ll mxfl = 0;
while(bfs())
mxfl += dfs(S, INF);
return mxfl;
}
signed main() { //freopen("data.in", "r", stdin);
ll sum = 0;
read(n, m, g); tot = n; S = ++tot; T = ++tot;
for(int i = 1; i <= n; ++i) read(a[i]);
for(int i = 1; i <= n; ++i) read(v[i]);
for(int i = 1; i <= n; ++i) {
if(!a[i]) add(S, i, v[i]);
else add(i, T, v[i]);
}
for(int i = 1; i <= m; ++i) {
int p = ++tot, to, W, k, f; read(to, W, k); vi vec;
for(int j = 1, x; j <= k; ++j) {
read(x);
if(!to) add(p, x, INF);
else add(x, p, INF);
}
read(f);
if(f) W += g, sum -= g;
sum += W;
if(!to) add(S, p, W);
else add(p, T, W);
}
printf("%lld\n", sum - dinic());
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?