Luogu2046 NOI2010 海拔 - 网络流 - 最短路 -
题目链接:https://www.luogu.com.cn/problem/P2046
首先观察可以发现最优解一定是左上部分是全0,右下是全1这样的形式
然后题目就相当于让我们求一个 的最小割
由于这是网格图(属于平面图)。平面图最小割 = 对偶图最短路
于是转化成对偶图求最短路,那么如何建图呢?
我们不妨把前n行前n列抽出来,然后用一个矩形左上角的那个点的坐标记为这个矩形的坐标。这样我们就表示出了 个小矩形
然后边有4种,这里取 和 为例
:这里是从东往西走,注意这个割对应的最短路一定是从右上往左下走的,所以 A->B 对应的鸽就是从下往上的了,也就是说,如果 那么建图的时候就是下格子(坐标为B点坐标) 连向上格子(坐标为A点坐标都减去1)
同理。这里是从南往北走,对应的割的路线是左往右,也就是说 ,则连边为
建图之后跑一个最短路就行了
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 3e5 + 5;
int n, s, t;
vector<pii>g[maxn];
int idx(int p,int q){return (p-1)*(n+1) + q;}
void add(int x,int y,int v){g[x].push_back(mpr(y,v));}
void add1(int x1,int y1,int x2,int y2,int v){
if(x1 == 0){
add(s,idx(x2,y2),v);
return ;
}
if(x2 == n+1){
add(idx(x1,y1),t,v);
return ;
}
add(idx(x1,y1), idx(x2,y2), v);
}
void add2(int x1,int y1,int x2,int y2,int v){
if(x1 == n+1){
add(t,idx(x2,y2),v);
return ;
}
if(x2 == 0){
add(idx(x1,y1),s,v);
return ;
}
add(idx(x1,y1), idx(x2,y2), v);
}
void add3(int x1,int y1,int x2,int y2,int v){
if(y2 == 0){
add(idx(x1,y1),t,v);
return ;
}
if(y1 == n+1){
add(s,idx(x2,y2),v);
return ;
}
add(idx(x1,y1), idx(x2,y2), v);
}
void add4(int x1,int y1,int x2,int y2,int v){
// debug();
if(y1 == 0){
add(t,idx(x2,y2),v);
return ;
}
if(y2 == n+1){
add(idx(x1,y1),s,v);
return ;
}
add(idx(x1,y1), idx(x2,y2), v);
}
struct iedges{int val,num;bool operator<(const iedges a)const{return a.val<val;}iedges(){}iedges(int vv,int nu):val(vv),num(nu){}};
priority_queue<iedges>pq;
int vis[maxn],dis[maxn];
void dijkstra(int be){
int N=(n+1)*(n+1)+3;
for(int i=1;i<=N;i++)dis[i]=inf;
dis[be]=0;
pq.push(iedges(0,be));
while(!pq.empty()){
int fr=pq.top().num;pq.pop();
if(vis[fr])continue;
vis[fr]=1;
for(pii now : g[fr]){
int u=now.first,v=now.second;
if(dis[fr]+v<dis[u]){
dis[u]=dis[fr]+v;
pq.push(iedges(dis[u],u));
}
}
}
printf("%d\n",dis[t]);
}
signed main(){
scanf("%d",&n);
s = (n+1) * (n+1) + 1; t = s + 1;
for(int i=1;i<=n+1;i++){ // w -> e
for(int j=1;j<=(n);j++){
int v;scanf("%d",&v);
// (i,j) -> (i,j+1) dual (i-1,j) -> (i,j)
add1(i-1,j,i,j,v);
}
}
for(int i=1;i<=n;i++){ // n -> s
for(int j=1;j<=n+1;j++){
int v;scanf("%d",&v);
// (i,j) -> (i+1,j) dual (i,j) -> (i,j-1)
add3(i,j,i,j-1,v);
}
}
for(int i=1;i<=n+1;i++){ // e -> w
for(int j=1;j<=(n);j++){
int v;scanf("%d",&v);
// (i,j+1) -> (i,j) dual (i,j) -> (i-1,j)
add2(i,j,i-1,j,v);
}
}
for(int i=1;i<=n;i++){ // s -> n
for(int j=1;j<=n+1;j++){
int v;scanf("%d",&v);
// (i+1,j) -> (i,j) dual (i,j-1) -> (i,j)
add4(i,j-1,i,j,v);
// debug();
}
}
dijkstra(s);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示