题意:有一些金矿区域,挖一个金矿时必须挖掉上边的跟他关联的,为最多赚的钱数。输入解释:第一个行是样例的组数。第二行表示有n个区域,接下来的一行m表示第i个区域的金矿的个数为m。接下来的m行为这个区域金矿花费的钱数,获得钱数,以及相关连的金矿的个数w,(下面的w行就是表示这些相关联的金矿的区域和在这个区域的第几个)。
建图:把点权为b(b>0)的连到源点,边权为b
点权为a(a<0)的连到汇点,边权为a
然后建出原图,原图中所有边权为inf
最后答案为 : 正点权和 - 最大流
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <queue>
#include <stdlib.h>
#include <cstdlib>
#include <math.h>
#include <set>
#include <vector>
#define inf 10000000000000000
#define eps 1e-8
#define N 2502
#define M 10500
#define ll __int64
using namespace std;
//M为边数 N为点数 点标从1-n
struct Edge{
ll from, to, cap, nex;
}edge[M*10];//注意这个一定要够大 不然会re 还有反向弧
ll head[N], edgenum;
void addedge(ll u, ll v, ll cap){
Edge E = { u, v, cap, head[u]};
edge[ edgenum ] = E;
head[u] = edgenum ++;
Edge E2= { v, u, 0, head[v]};
edge[ edgenum ] = E2;
head[v] = edgenum ++;
}
ll sign[N], s, t;
bool BFS(ll from, ll to){
memset(sign, -1, sizeof(sign));
sign[from] = 0;
queue<ll>q;
q.push(from);
while( !q.empty() ){
int u = q.front(); q.pop();
for(ll i = head[u]; i!=-1; i = edge[i].nex)
{
ll v = edge[i].to;
if(sign[v]==-1 && edge[i].cap)
{
sign[v] = sign[u] + 1, q.push(v);
if(sign[to] != -1)return true;
}
}
}
return false;
}
ll Stack[M*4], top, cur[M*4];
ll dinic(){
ll ans = 0;
while( BFS(s, t) )
{
memcpy(cur, head, sizeof(head));
ll u = s; top = 0;
while(1)
{
if(u == t)
{
ll flow = inf, loc;//loc 表示 Stack 中 cap 最小的边
for(ll i = 0; i < top; i++)
if(flow > edge[ Stack[i] ].cap)
{
flow = edge[Stack[i]].cap;
loc = i;
}
for(ll i = 0; i < top; i++)
{
edge[ Stack[i] ].cap -= flow;
edge[Stack[i]^1].cap += flow;
}
ans += flow;
top = loc;
u = edge[Stack[top]].from;
}
for(ll i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标
if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break;
if(cur[u] != -1)
{
Stack[top++] = cur[u];
u = edge[ cur[u] ].to;
}
else
{
if( top == 0 )break;
sign[u] = -1;
u = edge[ Stack[--top] ].from;
}
}
}
return ans;
}
vector<ll>G[N];
ll n, cnt;
void init(){
memset(head, -1, sizeof(head)); edgenum = 0;
cnt = 1;
for(ll i = 0; i <= n; i++)G[i].clear();
}
ll from, to;
int main(){
ll T, Cas = 1, i, j, k, m, a, b, u, v;scanf("%I64d",&T);
from = 0; to = 2501;
s = 0, t = to;
while(T--){
scanf("%I64d",&n);
init();
ll sum = 0;
for(i = 1; i <= n; i++){
scanf("%I64d",&m);
G[i].push_back(100000);
for(j = 1; j <= m; j++)
{
scanf("%I64d %I64d %I64d",&a,&b,&k);
G[i].push_back(cnt++);
sum += b;
addedge(from, G[i][j], b);
addedge(G[i][j], to, a);
while(k--){
scanf("%I64d %I64d",&u,&v);
addedge(G[i][j], G[u][v], inf);
}
}
}
printf("Case #%I64d: %I64d\n", Cas++, sum - dinic());
}
return 0;
}