P2045 方格取數加強版

2022-03-04 03:52:05 字數 1845 閱讀 8277

給出乙個n*n的矩陣,每一格有乙個非負整數aij,(aij <= 1000)現在從(1,1)出發,可以往右或者往下走,最後到達(n,n),每達到一格,把該格仔的數取出來,該格仔的數就變成0,這樣一共走k次,現在要求k次所達到的方格的數的和最大

輸入格式:

第一行兩個數n,k(1<=n<=50, 0<=k<=10)

接下來n行,每行n個數,分別表示矩陣的每個格仔的數

輸出格式:

乙個數,為最大和

輸入樣例#1:

3 1

1 2 3

0 2 1

1 4 2

輸出樣例#1:

11

每個格仔中的數不超過1000

solution:

本題費用流套路題(道道網路流題都是滿滿的套路啊!)。

分析怎麼想到費用流:

首先$k=1$就是sb動規,而當$k>1$就要限制每個點只能選$1$次,這樣限制了上下界且帶權的最優性問題,直接考慮費用流模型。

怎麼建模:

1、拆點肯定是要的,因為有選擇次數限制,那麼點$i$向$i'$連容量$1$費用為點權的邊,又因還能選k-1次,所以再從$i$向$i'$連容量$k-1$費用$0$的邊。

2、對於能轉移的一對點$i\rightarrow j$,從$i'$向$j$連容量$k$費用$0$的邊。

以$(1,1)$的入點為原點,$(n,n)$的出點為匯點,因為既保證了乙個點權值只會貢獻一次,也保證了選了k條路線(最大流一定為k),所以滿足正確性,直接跑最大費用最大流就好了。

**:

/*

code by 520 -- 8.25

*/#include

#define il inline

#define ll long long

#define re register

#define for(i,a,b) for(re int (i)=(a);(i)<=(b);(i)++)

#define bor(i,a,b) for(re int (i)=(b);(i)>=(a);(i)--)

#define debug printf("%d %s\n",__line__,__function__)

using

namespace

std;

const

int n=50005,inf=-2139062144

;int

n,k,s,t,maxn[n],pre[n],dis[n],tot;

int cnt=1

,h[n],to[n],net[n],w[n],c[n];

int maxc,maxf,mp[55][55],id[55][55

];bool

vis[n];

il void add(int u,int v,int fl,int

co)il

bool

spfa()

}return dis[t]!=inf;

}il

void

update()

maxf+=maxn[t],maxc+=maxn[t]*dis[t];

}il

void

init()

for(i,

1,n) for(j,1

,n)

while

(spfa()) update();

cout

<}int

main()

P2045 方格取數加強版

簡單的拆點 拆成入點和出點,對應點之間連一條cap 1,cost x和一條cap inf,cost 0的邊,然後相鄰點的出點和其他點的入點連邊,然後s有k的流量,然後跑最大費用最大流就好了 include include include include include using namespace...

洛谷P2045 方格取數加強版

傳送門 一看題意,發現第二次取就是0了,那麼就想到了網路流 其實是看標籤 費用流建圖 1.首先s向 1,1 連一條費用為0,容量k的邊 2.然後 n,n 向t連一條費用為0,容量k的邊 3.每個點 i,j 向 i 1,j 和 i,j 1 連一條費用0,容量k的邊 此處注意判邊界 4.每個點拆成入點和...

洛谷P2045 方格取數加強版

題目 link 網路流 費用流 一道比較好建模的題,重點是怎樣讓每個數隻被取一次 控制每個點被走的次數,我們可以很容易想到拆點 對於每個點,我們在入點和出點之間連兩條邊,一條流量為 1 11,費用為該格仔的權值 另一條流量為 infty 費用為 0 00。除此之外,每個點還要分別向右邊和下面的連邊,...