題目:link
網路流 - 費用流
一道比較好建模的題,重點是怎樣讓每個數隻被取一次
控制每個點被走的次數,我們可以很容易想到拆點
對於每個點,我們在入點和出點之間連兩條邊,一條流量為 1
11,費用為該格仔的權值;另一條流量為 ∞
\infty
∞,費用為 0
00。除此之外,每個點還要分別向右邊和下面的連邊,流量為 ∞
\infty
∞,費用為 000
最後,超級源點 s
ss 向點 (1,
1)
(1,1)
(1,1
) 連邊,且 (n,
n)
(n,n)
(n,n
) 向超級匯點 t
tt 連邊,流量為 k
kk,費用為 000
你也許會想到(像我一樣):如果在跑費用流時,先跑了 入點和出點之間的,流量為 ∞
\infty
∞ 的邊(也就是第一次到達方格時沒有取數)
然而,這種情況是不可能的。因為最大費用流最大流是以費用為邊權求最長路,所以一定會挑費用高的走,就不可能出現以上情況了
**:
#include
#include
#include
#include
using
namespace std;
const
int maxn=
5000+20
,maxm=
30000+10
,inf=
0x3f3f3f3f
;int nxt[maxm]
,to[maxm]
,flow[maxm]
,cost[maxm]
;int head[maxn]
,dis[maxn]
,pre[maxn]
,cur[maxn]
;bool vis[maxn]
;int n,m,k,s,t,ans;
int edgecnt=1;
inline
intread()
while
(ch>=
'0'&& ch<=
'9')s=
(s<<3)
+(s<<1)
+(ch^48)
,ch=
getchar()
;return s*w;
}inline
void
add(
int x,
int y,
int v,
int c)
inline
intid
(int x,
int y)
bool
spfa()
}}if(dis[t]
==-inf)
return0;
return1;
}void
upd(
) ans+
=cur[t]
*dis[t];}
intmain()
if(j!=m)}}
while
(spfa()
)upd()
;printf
("%d\n"
,ans)
;return0;
}
洛谷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 方格取數加強版
給出乙個n n的矩陣,每一格有乙個非負整數aij,aij 1000 現在從 1,1 出發,可以往右或者往下走,最後到達 n,n 每達到一格,把該格仔的數取出來,該格仔的數就變成0,這樣一共走k次,現在要求k次所達到的方格的數的和最大 輸入格式 第一行兩個數n,k 1 n 50,0 k 10 接下來n...
P2045 方格取數加強版
簡單的拆點 拆成入點和出點,對應點之間連一條cap 1,cost x和一條cap inf,cost 0的邊,然後相鄰點的出點和其他點的入點連邊,然後s有k的流量,然後跑最大費用最大流就好了 include include include include include using namespace...