UESTC 2014 Summer Training #11 Div.1 C
二分图带权最大匹配,不要求完备匹配
#include <cstdio>
#include <deque>
#include <set>
#include <string>
#include <map>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
#define Debug(x) (cerr << #x << " = " << (x) << endl)
#define Debug2(x, y) (cerr << #x << " = " << (x) << ", " << #y << " = " << (y) << endl)
#define FORIT(it,c) for(__typeof((c).begin())it=(c).begin();it!=(c).end();it++)
template<class T> inline T& RD(T &x){
char c; for (c = getchar(); c < '0'; c = getchar()); x = c - '0'; for (c = getchar(); '0' <= c && c <= '9'; c = getchar()) x = x * 10 + c - '0';
return x;
}
inline void outarray(int ar[], int n){
for (int i = 0; i<n; i++){
printf("%d%c", ar[i], i == n - 1 ? '\n' : ' ');
}
}
const int maxn = 60 * 2;
const int mod = 1e9 + 7;
const int maxe = maxn*maxn * 2;
const int inf = 0x3f3f3f3f;
int n, m;
int x[maxn], v[maxn];
int g[maxn][30];
bool dp[10000005];
struct edge{
int v, f, nxt, c;
edge(){}
edge(int v, int f, int nxt, int c) :v(v), f(f), nxt(nxt), c(c){}
}e[maxe];
int head[maxn], nume;
int src, sink;
void init(){
memset(head, -1, sizeof(head));
nume = 0;
}
void addedge(int u, int v, int f, int c){
//printf("%d %d %d %d\n", u, v, f, c);
e[nume] = edge(v, f, head[u], c);
head[u] = nume++;
e[nume] = edge(u, 0, head[v], -c);
head[v] = nume++;
}
int dist[maxn];
bool inq[maxn];
int pree[maxn];
int prevv[maxn];
bool spfa(){
queue<int> q;
memset(dist, 0x3f, sizeof(dist));
memset(inq, false, sizeof(inq));
memset(prevv, -1, sizeof(prevv));
dist[src] = 0;
q.push(src);
inq[src] = true;
while (!q.empty()){
int u = q.front(); q.pop();
inq[u] = false;
//Debug2(u,dist[u]);
for (int i = head[u]; ~i; i = e[i].nxt){
int v = e[i].v;
int c = e[i].c;
//Debug(v);
if (e[i].f > 0 && dist[u] + c < dist[v]){
dist[v] = dist[u] + c;
prevv[v] = u;
pree[v] = i;
if (inq[v] == false){
inq[v] = true;
q.push(v);
}
}
}
}
//Debug(dist[sink]);
if (prevv[sink] == -1)return false;
else return true;
}
int mincostflow(int &cost){
int flow = 0;
cost = 0;
while (spfa()){
int delta = inf;
for (int i = sink; i != src; i = prevv[i]){
delta = min(delta, e[pree[i]].f);
}
for (int i = sink; i != src; i = prevv[i]){
//delta = min(delta, pree[i].f);
e[pree[i]].f -= delta;
e[pree[i] ^ 1].f += delta;
}
cost += dist[sink] * delta;
flow += delta;
}
return flow;
}
int a1[1 << 14];
int a2[1 << 14];
int main(){
int T;
cin >> T;
while (T--){
scanf("%d%d", &m, &n);
init();
int _max = 0;
for (int i = 0; i < m; i++){
scanf("%d", &v[i]);
_max = max(v[i], _max);
}
for (int i = 0; i < n; i++){
scanf("%d", &x[i]);
for (int j = 0; j < x[i]; j++){
scanf("%d", &g[i][j]);
}
}
src = n + m;
sink = n + m + 1;
for (int i = 0; i < m; i++){
addedge(src, i, 1, 0);
addedge(i, sink, 1, 0);
}
for (int i = 0; i < n; i++){
addedge(i + m, sink, 1, 0);
}
for (int i = 0; i < n; i++){
int n1 = x[i] / 2;
int n2 = x[i] - n1;
memset(a1, 0, sizeof(a1));
memset(a2, 0, sizeof(a2));
for (int j = 1; j < 1 << n1; j++){
for (int k = 0; k < n1; k++){
if ((j >> k) & 1){
a1[j] = a1[j&~(1 << k)] + g[i][k];
break;
}
}
}
for (int j = 1; j < 1 << n2; j++){
for (int k = 0; k < n2; k++){
if ((j >> k) & 1){
a2[j] = a2[j&~(1 << k)] + g[i][n1+k];
break;
}
}
}
sort(a1,a1+(1<<n1));
sort(a2,a2+(1<<n2));
for (int j = 0; j < m; j++){
int k=0,z=(1<<n2)-1;
while(k < 1<<n1 && z >= 0){
if(a1[k]+a2[z]>v[j])z--;
else if(a1[k]+a2[z]<v[j])k++;
else {
addedge(j, i + m, 1, -v[j]);
break;
}
}
}
}
int cost;
mincostflow(cost);
cout << -cost << endl;
}
}