我发现我学的最大权闭合子图一直是假的,自闭了。
最大权闭合子图:选一点之前一定要选这个点的后继
$S$连正,负连$T$,边权为点权的绝对值。
题面
题解
注意离散化之后的二分答案,$n$应该是压缩后的$n$,即$tot$。
#include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 10050 #define INF 1000000007 #define S 0 #define T (cc+1) #define LL long long #define ri register int using namespace std; int n,m,tot,cc; int a[145],d[145][145],dct[145]; int bh[145][145]; bool vis[145]; inline int read() { int ret=0,f=0; char ch=getchar(); while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0' && ch<='9') ret*=10,ret+=(ch-'0'),ch=getchar(); return f?-ret:ret; } struct graph { vector<int> ed[N],w,to; int d[N],cur[N],p[N]; void add_edge(int u,int v,int tw) { to.push_back(v); w.push_back(tw); ed[u].push_back(to.size()-1); to.push_back(u); w.push_back(0); ed[v].push_back(to.size()-1); } bool bfs() { queue<int> q; memset(d,0x3f,sizeof(d)); d[S]=0; q.push(S); while (!q.empty()) { int x=q.front(); q.pop(); for (ri i=0;i<ed[x].size();i++) { int e=ed[x][i]; if (d[x]+1<d[to[e]] && w[e]) { d[to[e]]=d[x]+1; q.push(to[e]); } } } return d[T]<INF; } int dfs(int x,int limit) { if (x==T || limit==0) return limit; int sum=0; for (ri &i=cur[x];i<ed[x].size();i++) { int e=ed[x][i]; if (w[e] && d[x]+1==d[to[e]]) { int f=dfs(to[e],min(limit,w[e])); if (!f) continue; sum+=f; limit-=f; w[e]-=f; w[1^e]+=f; if (!limit) return sum; } } return sum; } int dinic() { int ret=0; while (bfs()) { memset(cur,0,sizeof(cur)); ret+=dfs(S,INF); } return ret; } } G; int main() { n=read(); m=read(); for (ri i=1;i<=n;i++) a[i]=read(); int sum=0; for (ri i=1;i<=n;i++) { for (ri j=i;j<=n;j++) { d[i][j]=read(); if (d[i][j]>0) sum+=d[i][j]; } } for (ri i=1;i<=n;i++) dct[i]=a[i]; sort(dct+1,dct+n+1); tot=unique(dct+1,dct+n+1)-dct-1; cc=tot; for (ri i=1;i<=n;i++) bh[i][i]=++cc; for (ri i=1;i<n;i++) for (ri j=i+1;j<=n;j++) bh[i][j]=++cc; for (ri i=1;i<=n;i++) { int x=lower_bound(dct+1,dct+tot+1,a[i])-dct; if (!vis[x]) { vis[x]=1; if (m) G.add_edge(x,T,a[i]*a[i]); } G.add_edge(bh[i][i],T,a[i]); G.add_edge(bh[i][i],x,INF); } for (ri i=1;i<=n;i++) for (ri j=i;j<=n;j++) if (d[i][j]>0) G.add_edge(S,bh[i][j],d[i][j]); else G.add_edge(bh[i][j],T,-d[i][j]); for (ri i=1;i<n;i++) for (ri j=i+1;j<=n;j++) { G.add_edge(bh[i][j],bh[i+1][j],INF); G.add_edge(bh[i][j],bh[i][j-1],INF); } cout<<sum-G.dinic()<<endl; }