最小代价一看就是拆点最大流 问题在于如何求字典序的方案
如何判断一条边是否是割边是很容易的 只需要从u出发看是否能找到一条u到v的增广路,如果存在这样的一条路径 说明该边不是割边
那么我们按照C的大小来枚举每一条边 如果该边是割边 那么我们就要把它从图中删除(这样可以让一些割边不再是满流的边 这些删除的割边都是一定不与当前割边在同一割集中的割边 要让这样的边不能入选)
那么我们要怎样最快的消除这条边呢?我们使用退流算法 从T到v跑一次最大流 从u到S跑一遍最大流即可消除当前边的影响 再把当前边的容量设置为0
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define SF scanf
#define PF printf
#define mp make_pair
#define fir first
#define sec second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 700;
const int MAXM = (MAXN * MAXN / 2) + MAXN;
const int INF = 0x3f3f3f3f;;
struct Node {
int u, v, next, c;
} ;
struct ISAP {
Node Edge[MAXM*2+10];
int adj[MAXN*2+10], gap[MAXN*2+10], d[MAXN*2+10], ecnt;
int n, m, s, t;
void addedge(int u, int v, int c) {
Node &e = Edge[ecnt];
e.u = u; e.v = v; e.c = c; e.next = adj[u];
adj[u] = ecnt++;
}
void add(int u, int v, int c) {
addedge(u, v, c); addedge(v, u, 0);
}
int aug(int u, int inc) {
int mindis = n-1, Inc = 0;
if(u == t) return inc;
for(int i = adj[u]; ~i; i = Edge[i].next) {
Node &e = Edge[i];
int v = e.v, c = e.c;
if(c) {
if(d[v] == d[u]-1) {
int del = min(inc-Inc, c);
del = aug(v, del);
Inc += del;
Edge[i].c -= del;
Edge[i^1].c += del;
if(d[s] >= n) return Inc;
if(Inc == inc) return Inc;
}
mindis = min(mindis, d[v]);
}
}
if(!Inc) {
gap[d[u]]--;
if(!gap[d[u]]) d[s] = n;
d[u] = mindis+1;
gap[d[u]]++;
}
return Inc;
}
void init_dis() {
queue <int> q;
memset(d, 0, sizeof(d));
memset(gap, 0, sizeof(gap));
q.push(t);
while(!q.empty()) {
int u = q.front(); q.pop();
gap[d[u]]++;
for(int i = adj[u]; ~i; i = Edge[i].next) {
int v = Edge[i].v;
if(!d[v] && v != t) {
d[v] = d[u] + 1; q.push(v);
}
}
}
}
int MaxFlow(int _s, int _t, int _n) {
s = _s; t = _t; n = _n;
int Flow = 0;
init_dis();
while(d[s] < n) Flow += aug(s, INF);
return Flow;
}
void init() {
memset(adj, -1, sizeof(adj));
ecnt = 0;
}
bool bfs(int x, int y) {
queue <int> q;
memset(d, 0, sizeof(d));
d[x] = 1; q.push(x);
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = adj[u]; ~i; i = Edge[i].next) {
int v = Edge[i].v;
if(!d[v] && Edge[i].c) d[v] = 1, q.push(v);
}
}
return d[y];
}
} sap;
int A[MAXN+10], f[MAXN+10], B[MAXN+10], n, MAX, S, T;
pii C[MAXN+10];
void dp() {
for(int i = 1; i <= n; i++) {
f[i] = 1;
for(int j = 1; j < i; j++)
if(A[j] < A[i])
f[i] = max(f[i], f[j]+1);
MAX = max(MAX, f[i]);
}
}
void Build_Graph() {
for(int i = 1; i <= n; i++) sap.add(i, n+i, B[i]);
for(int i = 1; i <= n; i++) {
if(f[i] == 1) sap.add(S, i, INF);
if(f[i] == MAX) sap.add(n+i, T, INF);
for(int j = i+1; j <= n; j++)
if(f[j] == f[i]+1 && A[j] > A[i])
sap.add(n+i, j, INF);
}
}
vector <int> ans;
int main()
{
int _T; SF("%d", &_T); while(_T--) {
sap.init();
ans.clear();
MAX = 0;
SF("%d", &n);
S = 2*n+1; T = S+1;
for(int i = 1; i <= n; i++) SF("%d", &A[i]);
for(int i = 1; i <= n; i++) SF("%d", &B[i]);
for(int i = 1; i <= n; i++) SF("%d", &C[i].fir), C[i].sec = i;
dp();
Build_Graph();
int mincost = sap.MaxFlow(S, T, T);
sort(C+1, C+1+n);
for(int i = 1; i <= n; i++) {
int x = C[i].sec;
if(sap.Edge[(x-1)*2].c || sap.bfs(x, x+n)) continue;
ans.push_back(x);
sap.MaxFlow(x, S, T); sap.MaxFlow(T, x+n, T);
sap.Edge[(x-1)*2^1].c = sap.Edge[(x-1)*2].c = 0;
}
PF("%d %d\n", mincost, (int)ans.size());
sort(ans.begin(), ans.end());
for(int i = 0; i < ans.size(); i++)
PF("%d%c", ans[i], (i == ans.size()-1) ? '\n' : ' ');
}
}
/*
2
6
3 4 4 2 2 3
2 1 1 1 1 2
6 5 4 3 2 1
6
3 4 4 2 2 3
2 1 1 1 1 2
6 5 4 3 2 1
*/