您的位置:首页 > 其它

Codeforces contest 311 problem E. Biologist(最大权闭合子图)

2018-01-29 15:30 295 查看

传送门

题目大意



题解

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;
}


人生又是什麼呢 只是不明不白地活著
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: