「题解」Codeforces 1427G One Billion Shades of Grey

· · 题解

感谢 127 的指导/ll

$$ \min \{\sum_{(u,v)}\max(0,h_u-h_v+w_{u,v})c_{u,v}\} $$ 对偶一下,问题就变为:如果两个格子相邻就互相连容量为 $c_{u,v}=1$,费用为 $w_{u,v}=0$ 的边,跑最大费用循环流。 为了限制边界上那些格子 $h$ 取得就是其 $a_{i,j}$,建立一个点 $S$ 代表零势点,连边 $S\to u$,容量为 $+\infty$,费用为 $a_{i,j}$;连边 $u\to S$,容量为 $+\infty$,费用为 $-a_{i,j}$。(这里 $c=\infty$ 是为了限制对偶前问题里那个绝对值必须取 $0$)。 如果将边界内部的费用提前统计好,$c=1,w=0$ 的边仅在边界与内部,内部与内部之间连边。那么边界只有一条出边。所以边界与 $S$ 之间的容量可以视作 $1$。 为了跑最大费用循环流,将边界 $\to S$ 的边改成边界到 $\to$ 汇点 $T$ 的边,跑最大费用可行流就行。 想要优化的话就考虑从大往小对 $S$ 的出点开始进行 bfs,在能走到的路径里面选择最优的那一条增广。每次增广完 $S$ 的出边和 $T$ 的入边就会有一条失效。所以总复杂度是 $\mathcal{O}(n^3)$ 的。 ```cpp #include<cstdio> #include<vector> #include<queue> #include<cstring> #include<iostream> #include<algorithm> #include<ctime> #include<random> #include<assert.h> #define pb emplace_back #define mp make_pair #define fi first #define se second #define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<<x<<'\n' #define dpi(x,y) cerr<<"In Line "<<__LINE__<<" the "<<#x<<" = "<<x<<" ; "<<"the "<<#y<<" = "<<y<<'\n' #define DE(fmt,...) fprintf(stderr, "Line %d : " fmt "\n",__LINE__,##__VA_ARGS__) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int>pii; typedef pair<ll,int>pli; typedef pair<ll,ll>pll; typedef pair<int,ll>pil; typedef vector<int>vi; typedef vector<ll>vll; typedef vector<pii>vpii; typedef vector<pll>vpll; template<typename T>T cmax(T &x, T y){return x=x>y?x:y;} template<typename T>T cmin(T &x, T y){return x=x<y?x:y;} template<typename T> T &read(T &r){ r=0;bool w=0;char ch=getchar(); while(ch<'0'||ch>'9')w=ch=='-'?1:0,ch=getchar(); while(ch>='0'&&ch<='9')r=r*10+(ch^48),ch=getchar(); return r=w?-r:r; } template<typename T1,typename... T2> void read(T1 &x,T2& ...y){read(x);read(y...);} const int N=210; const int inf=0x7fffffff; const ll INF=0x7fffffffffffffff; int tot; int head[N*N],ent=1; int n,p[N][N],a[N][N]; int ok[N*N],pre[N*N],fro[N*N]; int dx[]={1,-1,0,0}; int dy[]={0,0,1,-1}; vpii vec; struct Edge{ int to,nxt; int w; }e[(N*N)<<3]; inline void adde(int x,int y){ e[++ent]={y,head[x],1};head[x]=ent; e[++ent]={x,head[y],0};head[y]=ent; } void dfs(int x){ ok[x]=1; for(int i=head[x];i;i=e[i].nxt){ int v=e[i].to,w=e[i].w; if(!w||ok[v])continue; pre[v]=i;fro[v]=x; dfs(v); } } ll MC(){ sort(vec.begin(),vec.end(),[&](pii x,pii y){return a[x.fi][x.se]>a[y.fi][y.se];}); ll s=0; for(auto [u,v]:vec){ for(int i=1;i<=tot;i++)ok[i]=pre[i]=0; dfs(p[u][v]); int o=0,c=-inf; for(auto [x,y]:vec){ if(ok[p[x][y]]&&-a[x][y]>c){ c=-a[x][y]; o=p[x][y]; } } if(c==-inf)continue; if(a[u][v]+c<0)continue; s+=a[u][v]+c; while(o!=p[u][v]){ int ep=pre[o]; e[ep].w^=1;e[ep^1].w^=1; o=fro[o]; } } return s; } signed main(){ read(n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) read(a[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(a[i][j]>=0) p[i][j]=++tot; ll ans=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(a[i][j]>=0){ if(a[i][j]>0){ vec.pb(mp(i,j)); } for(int o=0;o<4;o++){ int x=i+dx[o],y=j+dy[o]; if(a[i][j]>0&&a[x][y]>0)ans+=abs(a[i][j]-a[x][y]); else{ if(a[x][y]>=0){ adde(p[i][j],p[x][y]); } } } } ans/=2; ans+=MC(); cout<<ans<<'\n'; return 0; } ```