网络流 求一个字典序最小的最小割
P3308 [SDOI2014]LIS
[SDOI2014]LIS(https://www.luogu.com.cn/problem/P3308)
题目描述
给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若干项,使得A的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。 如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。
输入格式
输入包含多组数据。
输入的第一行包含整数T,表示数据组数。接下来4*T行描述每组数据。
每组数据的第一行包含一个整数N,表示A的项数。
接下来三行,每行N个整数A1..An,B1.,Bn,C1..Cn,满足1 < =Ai,Bi,Ci < =10^9,且Ci两两不同。
输出格式
对每组数据,输出两行。第一行包含两个整数S,M,依次表示删去项的代价和与数量;接下来一行M个整数,表示删去项在A中的的位置,按升序输出。
输入输出样例
输入
1
6
3 4 4 2 2 3
2 1 1 1 1 2
6 5 4 3 2 1
输出
4 3
2 3 6
说明/提示
【样例说明】
解释:删去(A2,43,A6),(A1,A6),(A2,43,44,A5)等都是合法的方案,但{A2,43,A6)对应的C值的字典序最小。
1 < =N < =700 T < =5
思路:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1500 + 10;
const int INF = 0x3f3f3f3f;
//注释为弧优化
struct node {
int form, to, cap, flow, next;
} edge[5000005];
int head[maxn];
int cnt;
struct max_Folw {
int d[maxn], cur[maxn], start, tend;
bool vis[maxn];
void init() {
memset(head, -1, sizeof(head));
cnt=0;
}
void add(int start, int to, int cap) {
edge[cnt].form = start;
edge[cnt].to = to;
edge[cnt].cap = cap;
edge[cnt].flow = 0;
edge[cnt].next = head[start];
head[start] = cnt++;
}
void AddEdge(int start, int to, int cap) {
//cout<<start<<" "<<to<<" "<<cap<<endl;
add(start, to, cap);
add(to, start, 0);
}
bool BFS() {
memset(d, -1, sizeof(d));
int Q[maxn * 2];
int Thead, Ttail;
Thead = Ttail = 0;
Q[Ttail++] = tend;
d[tend] = 0;
while (Thead<Ttail) {
int x = Q[Thead];
if (x == start)
return true;
for (int i = head[x]; i != -1; i = edge[i].next) {
int temp = edge[i].to;
if (d[temp] == -1 && edge[i^1].cap > edge[i^1].flow) { //没有标记,且可行流大于0
d[temp] = d[x] + 1;
Q[Ttail++] = temp;
}
}
Thead++;
}
return false;//汇点是否成功标号,也就是说是否找到增广路
}
int DFS(int x, int cap) {
if (x == tend)
return cap;
int flow = 0, f;
//for (int i = cur[x]; i != -1; i = edge[cur[x]=i].next) {
for (int i = head[x]; i != -1; i = edge[i].next) {
int temp = edge[i].to;
if (d[temp] == d[x] - 1 && edge[i].cap > edge[i].flow) {
f = DFS(temp, min(cap - flow, edge[i].cap - edge[i].flow));
edge[i].flow += f;
edge[i ^ 1].flow -= f;
flow += f;
if (flow == cap)
return flow;
}
}
d[x] = -2;//防止重搜
return flow;
}
int maxflow(int s, int t) {
start=s, tend=t;
int flow = 0, f;
while (BFS()) {
//memcpy(cur, head, sizeof head);
flow += DFS(start, INF);
}
return flow;
}
queue<int> q;
int bfs(int s, int t){
memset(vis, 0, sizeof(vis));
while(!q.empty()) q.pop();
q.push(s); vis[s]=1;
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=head[u]; i!=-1; i=edge[i].next){
int to=edge[i].to;
if(edge[i].cap-edge[i].flow!=0&&vis[to]==0){
q.push(to); vis[to]=1;
if(to==t) return 1;
}
}
}
return 0;
}
} flow;
int a[1505], b[1505];
struct Node{
int c, id;
}c[1505];
int f[1505], id[1505];
vector<int> ans;
int main(){
int t; scanf("%d", &t);
while(t--){
memset(f, 0, sizeof(f));
memset(id, 0, sizeof(id));
ans.clear();
int n; scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
}
for(int i=1; i<=n; i++){
scanf("%d", &b[i]);
}
for(int i=1; i<=n; i++){
scanf("%d", &c[i].c);
c[i].id=i;
}
int mx=0;
for(int i=1; i<=n; i++){
f[i]=1;
for(int j=i-1; j>=1; j--){
if(a[j]<a[i]){
f[i]=max(f[i], f[j]+1);
mx=max(mx, f[i]);
}
}
}
flow.init();
for(int i=1; i<=n; i++){
flow.AddEdge(i, i+n, b[i]);
id[i]=cnt-2;
//cout<<i<<"="<<edge[id[i]].form<<" "<<edge[id[i]].to<<endl;
if(f[i]==1){
flow.AddEdge(0, i, INF);
}
if(f[i]==mx){
flow.AddEdge(i+n, 2*n+1, INF);
}
for(int j=i+1; j<=n; j++){
if(a[i]<a[j]&&f[i]+1==f[j]){
flow.AddEdge(i+n, j, INF);
}
}
}
printf("%d ", flow.maxflow(0, 2*n+1));
sort(c+1, c+n+1, [](Node &a, Node &b){return a.c<b.c;});
for(int i=1; i<=n; i++){
int x=c[i].id, y=c[i].id+n;
if(edge[id[c[i].id]].cap-edge[id[c[i].id]].flow==0&&!flow.bfs(x, y)){
ans.push_back(c[i].id);
//退流
flow.maxflow(2*n+1, y);
flow.maxflow(x, 0);
edge[id[c[i].id]].cap=edge[id[c[i].id]].flow=0;
edge[id[c[i].id]^1].cap=edge[id[c[i].id]^1].flow=0;
}
}
printf("%d\n", ans.size());
sort(ans.begin(), ans.end());
for(auto x: ans){
printf("%d ", x);
}
printf("\n");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)