洛谷 P9545 [湖北省选模拟 2023] 环山危路 / road
最大流转最小割,然后钦定一个点集 \(S\) 表示和源点连通的点,点集 \(T\) 表示其他点,记 \(F (S, T)\) 表示 \(S\) 到 \(T\) 的最小割。
注意到 \(F (S, T) + F (T, S) = |S| \times |T|\) 为定值,故我们希望最小化 \(F (S, T) - F (T, S) = \sum _ {i \in S} out _ i - in _ i\),上述等式成立是因为 \(S\) 内部的贡献都自己抵消掉了。所以枚举 \(|S|\),取最小的几个 \(out _ i - in _ i\) 加入 \(S\) 即可。
#include<cstdio>
#include<algorithm>
#define N 3005
using namespace std;
int n,q,m,deg[N],S[N];
char s[N][N];
bool ban[N];
struct node {
int x,id;
bool operator<(node a) {return x<a.x;}
} d[N];
int solve(int k) {
int cnt=0,sum=0;
for(int i=1;i<=k;i++) cnt++,sum+=deg[S[i]];
int res=(cnt*(n-cnt)+sum)/2;
for(int i=1;i<=n;i++) if(!ban[d[i].id]) {
cnt++,sum+=d[i].x,res=min(res,(cnt*(n-cnt)+sum)/2);
}
return res;
}
int main() {
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) {
scanf("%s",s[i]+1);
for(int j=1;j<=n;j++) if(s[i][j]=='1') deg[i]++,deg[j]--;
}
for(int i=1;i<=n;i++) d[i].x=deg[i],d[i].id=i;
sort(d+1,d+n+1);
for(int i=1,k,T;i<=q;i++) {
scanf("%d%d",&T,&k),ban[T]=1;
for(int j=1;j<=k;j++) scanf("%d",&S[j]),ban[S[j]]=1;
printf("%d\n",solve(k)),ban[T]=0;
for(int j=1;j<=k;j++) ban[S[j]]=0;
}
return 0;
}

浙公网安备 33010602011771号