小M的作物 最小割最大流
题目描述
小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号)。
现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植可以获得bi的收益,而且,现在还有这么一种神奇的现象,就是某些作物共同种在一块耕地中可以获得额外的收益,小M找到了规则中共有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以获得c2i的额外收益。
小M很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?
输入输出格式
输入格式:
第一行包括一个整数n
第二行包括n个整数,表示ai第三行包括n个整数,表示bi第四行包括一个整数m接下来m行,
对于接下来的第i行:第一个整数ki,表示第i个作物组合中共有ki种作物,
接下来两个整数c1i,c2i,接下来ki个整数,表示该组合中的作物编号。
输出格式:
只有一行,包括一个整数,表示最大收益
输入输出样例
说明
样例解释
A耕地种1,2,B耕地种3,收益4+2+3+2=11。
数据范围与约定
1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。
建立源点和汇点后,我们很容易构造ai,bi的收益方式:
将源点s与i连ai边,i与汇点t连bi边;
由于题目中还有ci的收益方式,我们可以设立一个虚节点x:
将s与x连c1i容量的边,接着x与这个组合中所有的点连inf的边,
然后该组合中所有的点与另一个虚节点y连inf容量的边,最后y与t连c2i容量的边;
跑一下dinic即可;
#include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<vector> #include<queue> #include<bitset> #include<ctime> #include<time.h> #include<deque> #include<stack> #include<functional> #include<sstream> //#include<cctype> //#pragma GCC optimize(2) using namespace std; #define maxn 20005 #define inf 0x7fffffff //#define INF 1e18 #define rdint(x) scanf("%d",&x) #define rdllt(x) scanf("%lld",&x) #define rdult(x) scanf("%lu",&x) #define rdlf(x) scanf("%lf",&x) #define rdstr(x) scanf("%s",x) #define mclr(x,a) memset((x),a,sizeof(x)) typedef long long ll; typedef unsigned long long ull; typedef unsigned int U; #define ms(x) memset((x),0,sizeof(x)) const long long int mod = 1e9 + 7; #define Mod 1000000000 #define sq(x) (x)*(x) #define eps 1e-5 typedef pair<int, int> pii; #define pi acos(-1.0) //const int N = 1005; #define REP(i,n) for(int i=0;i<(n);i++) typedef pair<int, int> pii; inline int rd() { int x = 0; char c = getchar(); bool f = false; while (!isdigit(c)) { if (c == '-') f = true; c = getchar(); } while (isdigit(c)) { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return f ? -x : x; } ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a%b); } int sqr(int x) { return x * x; } /*ll ans; ll exgcd(ll a, ll b, ll &x, ll &y) { if (!b) { x = 1; y = 0; return a; } ans = exgcd(b, a%b, x, y); ll t = x; x = y; y = t - a / b * y; return ans; } */ int n, m; int st, ed; struct node { int u, v, nxt, w; }edge[(int)(1e7 + 1)]; int head[1000003], cnt; void addedge(int u, int v, int w) { edge[cnt].u = u; edge[cnt].v = v; edge[cnt].nxt = head[u]; edge[cnt].w = w; head[u] = cnt++; } int rk[1000003]; int bfs() { queue<int>q; ms(rk); rk[st] = 1; q.push(st); while (!q.empty()) { int tmp = q.front(); q.pop(); for (int i = head[tmp]; i != -1; i = edge[i].nxt) { int to = edge[i].v; if (rk[to] || edge[i].w <= 0)continue; rk[to] = rk[tmp] + 1; q.push(to); } } return rk[ed]; } int dfs(int u, int flow) { if (u == ed)return flow; int add = 0; for (int i = head[u]; i != -1 && add < flow; i = edge[i].nxt) { int v = edge[i].v; if (rk[v] != rk[u] + 1 || !edge[i].w)continue; int tmpadd = dfs(v, min(edge[i].w, flow - add)); if (!tmpadd) { rk[v] = -1; continue; } edge[i].w -= tmpadd; edge[i ^ 1].w += tmpadd; add += tmpadd; } return add; } int ans; void dinic() { while (bfs())ans += dfs(st, inf); } int a[maxn], b[maxn]; int ID(int x,int p) { if (p == 1)return x; else if (p == 2)return (x + m); else if (p == 3)return (x + n + m); } int main() { // ios::sync_with_stdio(0); mclr(head, -1); n = rd(); int sum = 0; for (int i = 1; i <= n; i++)a[i] = rd(), sum += a[i]; for (int j = 1; j <= n; j++)b[j] = rd(), sum += b[j]; m = rd(); st = 0; ed = n + 2 * m + 2; for (int i = 1; i <= n; i++)addedge(st, ID(i, 2), a[i]), addedge(ID(i, 2), st, 0); for (int i = 1; i <= n; i++)addedge(ID(i, 2), ed, b[i]), addedge(ed, ID(i, 2), 0); for (int i = 1; i <= m; i++) { int k = rd(); int c1 = rd(), c2 = rd(); sum += (c1 + c2); while (k--) { int x = rd(); addedge(ID(i, 1), ID(x, 2), inf); addedge(ID(x, 2), ID(i, 1), 0); addedge(ID(x, 2), ID(i, 3), inf); addedge(ID(i, 3), ID(x, 2), 0); } addedge(st, ID(i, 1), c1); addedge(ID(i, 1), st, 0); addedge(ID(i, 3), ed, c2); addedge(ed, ID(i, 3), 0); } dinic(); printf("%d\n", sum - ans); return 0; }
EPFL - Fighting