传送门
题目大意
题解
GDKOI考成了垃圾,博客都不想写了,键盘都不想碰了,人生都觉得无意义了。
一个简单的最大权闭合子图的模型。按照套路,将条件和变量都建点。S代表0的选择集合,T是1的集合。对于每个变量,是0与S连,否则与T连,如果割掉代表要花费V[i]的代价;对于每个条件,先收集其价值,再在连边上放上其价值(+代价),如果割掉就代表不要这部分的价值(+付出代价)。
同样向S或T连边,再向要求的变量连边(或者变量连向条件),容量为INF,代表如果构成S-T路径就要舍弃条件或者修改所连变量的所有值。然后跑一遍最小割。
时间复杂度玄学。
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define maxn 100010
#define maxm 1000100
#define INF 0x7FFFFFFF
using namespace std;
int s, t, cur = -1;
struct List{
int obj, cap;
List *next, *rev;
}*head[maxn], *iter[maxn], Edg[maxm];
void Addedge(int a, int b, int c){
Edg[++cur].next = head[a];
Edg[cur].obj = b;
Edg[cur].cap = c;
Edg[cur].rev = Edg+(cur^1);
head[a] = Edg+cur;
}
int q[maxn], level[maxn];
bool bfs(){
int hh = 0, tt = 0;
for(int i = s; i <= t; i++) level[i] = -1;
level[s] = 0;
q[0] = s;
while(hh <= tt){
int now = q[hh++];
for(List *p = head[now]; p; p = p->next){
int v = p->obj, c = p->cap;
if(c && level[v] == -1){
level[v] = level[now] + 1;
q[++tt] = v;
}
}
}
return ~ level[t];
}
int Dinic(int now, int f){
if(now == t || !f) return f;
int ret = 0;
for(List *&p = iter[now]; p; p = p->next){
int v = p->obj, c = p->cap;
if(c && level[now] + 1 == level[v]){
int d = Dinic(v, min(f, c));
f -= d;
p->cap -=d;
ret += d;
p->rev->cap += d;
if(!f) break;
}
}
return ret;
}
int MinCut(){
int flow = 0;
while(bfs()){
for(int i = s; i <= t; i++) iter[i] = head[i];
flow += Dinic(s, INF);
}
return flow;
}
int sum;
int n, m, g;
int V[maxn], F[maxn];
int main(){
scanf("%d%d%d", &n, &m, &g);
for(int i = 1; i <= n; i++) scanf("%d", &F[i]);
for(int i = 1; i <= n; i++) scanf("%d", &V[i]);
s = 1; t = s + n + m + 1;
for(int i = s; i <= t; i++) head[i] = NULL;
for(int i = 1; i <= n; i++){
if(!F[i]){
Addedge(s, s+i, V[i]);
Addedge(s+i, s, 0);
}
else{
Addedge(s+i, t, V[i]);
Addedge(t, s+i, 0);
}
}
int f, w, k, x;
for(int i = 1; i <= m; i++){
scanf("%d%d%d", &f, &w, &k);
sum += w;
for(int j = 1; j <= k; j++){
scanf("%d", &x);
if(!f){
Addedge(s+n+i, s+x, INF);
Addedge(s+x, s+n+i, 0);
}
else{
Addedge(s+x, s+n+i, INF);
Addedge(s+n+i, s+x, 0);
}
}
scanf("%d", &x);
if(!f){
Addedge(s, s+n+i, w+g*x);
Addedge(s+n+i, s, 0);
}
else{
Addedge(s+n+i, t, w+g*x);
Addedge(t, s+n+i, 0);
}
}
printf("%d\n", sum - MinCut());
return 0;
}
人生又是什麼呢 只是不明不白地活著