考虑网络流建模。
一个飞行任务依赖于一些产品,所以可以将任务抽象为正权点,产品抽象为负权点,然后跑最大权闭合子图即可。
输出方案是一大难点。
考虑最大权闭合子图的基本模型:割掉\(S\)与正权点间的边表示不选它。所以在最后一次被封锁住的\(BFS\)中,所有没割掉的点(还有流量)一定会被\(BFS\)到,而后它的所有后继,由于连的都是\(INF\)边,所以肯定也会被\(BFS\)到。所以,最后一次\(BFS\)中有标号的点就是一组合法方案。
然后就做完了。
#include <bits/stdc++.h>
#define dbg(x) cerr << #x " = " << x << "\n"
#define INF 0x3f3f3f3f
typedef long long LL;
typedef long double ld;
typedef unsigned long long ULL;
using namespace std;
template < typename T > inline void inp(T& t) {
char c = getchar(); T x = 1; t = 0; while(!isdigit(c)) {if(c == '-') x = -1; c = getchar();}
while(isdigit(c)) t = t * 10 + c - '0' , c = getchar();t *= x;
}
template < typename T , typename... Args > inline void inp(T& t , Args&... args) {inp(t); inp(args...);}
template < typename T > inline void outp(T t) {
if(t < 0) putchar('-') , t = -t; T y = 10 , len = 1;
while(y <= t) y *= 10 , len++; while(len--) y /= 10 , putchar(t / y + 48) , t %= y;
}
template < typename T > inline T mul(T x , T y , T MOD) {x=x%MOD,y=y%MOD;return ((x*y-(T)(((ld)x*y+0.5)/MOD)*MOD)%MOD+MOD)%MOD;}
const int MAXN = 50000 + 10;
int d[MAXN] , p[MAXN] , s , t;
struct EdgeList {
int to[MAXN] , nxt[MAXN] , w[MAXN] , flow[MAXN] , head[MAXN] , gg[MAXN] , cnt;
EdgeList() { memset(head , -1 , sizeof(head)); cnt = 0; }
void AddEdge(int u , int v , int we) {
to[cnt] = v; w[cnt] = we; flow[cnt] = 0; nxt[cnt] = head[u]; head[u] = cnt++;
to[cnt] = u; w[cnt] = 0; flow[cnt] = 0; nxt[cnt] = head[v]; head[v] = cnt++;
}
}E;
bool bfs() {
queue < int > q;
for(int i = s; i <= t; i++) E.gg[i] = E.head[i] , d[i] = 0;
q.push(s); d[s] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = E.head[u]; i != -1; i = E.nxt[i]) {
int v = E.to[i] , w = E.w[i] , flow = E.flow[i];
if(w > flow && !d[v]) {
d[v] = d[u] + 1; q.push(v);
if(v == t) return 1;
}
}
}
return 0;
}
int dfs(int u , int cap) {
if(u == t || !cap) return cap;
int outcap = 0;
for(int i = E.head[u]; i != -1 && outcap < cap; i = E.nxt[i]) {
int v = E.to[i] , w = E.w[i] , flow = E.flow[i];
if(w > flow && d[v] == d[u] + 1) {
int tmpcap = dfs(v , min(cap - outcap , w - flow));
outcap += tmpcap; E.flow[i] += tmpcap; E.flow[i^1] -= tmpcap;
if(outcap == cap) break;
}
}
return outcap;
}
int RunDinic() { int ans = 0; while(bfs()) ans += dfs(s , INF); return ans; }
int m , n , pos[MAXN];
int main() {
inp(m , n); s = 0 , t = m + n + 1;
int ans = 0;
for(int i = 1; i <= m; i++) {
string x; getline(cin , x); vector < int > v; v.clear();
x = x + " ";
int num = 0;
for(int j = 0; j < x.size(); j++) {
if(x[j] == ' ') v.push_back(num) , num = 0;
else num = num * 10 + x[j] - '0';
}
for(int j = 1; j < v.size(); j++) E.AddEdge(i , m + v[j] , INF);
pos[i] = E.cnt;
E.AddEdge(s , i , v[0]); ans += v[0];
}
for(int i = 1; i <= n; i++)
inp(p[i]) , pos[m + i] = E.cnt , E.AddEdge(m + i , t , p[i]);
int x = ans - RunDinic();
for(int i = 1; i <= m; i++) if(d[i]) printf("%d " , i);
puts("");
for(int i = m + 1; i <= m + n; i++) if(d[i]) printf("%d " , i - m);
cout << "\n" << x << endl;
return 0;
}