傳送門
 
文章目錄
 
題意:
 
給你一個n?nn*nn?n的矩陣,有mmm個點的位置需要填數,填的數范圍是0≤k≤1e60\le k\le1e60≤k≤1e6,需要滿足第iii行的最大值是bib_ibi?,第iii列的最大值是cic_ici?,求一個滿足條件的最小代價。
 最小代價即填的數之和。
 n≤2e3,m≤8e5,k≤1e6,bi,ci≤kn\le2e3,m\le8e5,k\le1e6,b_i,c_i\le kn≤2e3,m≤8e5,k≤1e6,bi?,ci?≤k
 
思路:
 
我們從大到小考慮一個kkk,假設當前有xxx行以及yyy列需要滿足最大值是kkk,那么顯然我們可以直接選x+yx+yx+y個位置填上最大值,但是不難發現,這幾個位置有些是可以重復的,也就是說他們如果匹配的話可以少用一個最大值,直接按行列建二分圖跑一個最大匹配即可。假設跑出來的匹配數為zzz,那么答案就加上(x+y?z)?k(x+y-z)*k(x+y?z)?k。
 考慮次大值,由于題目保證一定有解,所以與最大值相同,直接跑二分圖匹配即可。因為就算與最大值填的位置有重疊,也可以修改最大值的位置,我們無需知道具體在哪里,只需要知道他們的貢獻即可。
 
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=5010,M
=N
*2,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,m
,k
;
int g
[2020][2020];
int b
[N
],c
[N
];struct Maxflow
{int S
,T
;int e
[M
],ne
[M
],w
[M
],h
[N
],hs
[N
],idx
;int depth
[N
];void init() { idx
=0; for(int i
=0;i
<=n
+n
+11;i
++) h
[i
]=-1; }inline void add(int a
,int b
,int c
){e
[idx
]=b
,w
[idx
]=c
,ne
[idx
]=h
[a
],h
[a
]=idx
++;e
[idx
]=a
,w
[idx
]=0,ne
[idx
]=h
[b
],h
[b
]=idx
++;}bool bfs(){memset(depth
,-1,sizeof (depth
)); depth
[S
]=0;queue
<int>q
; q
.push(S
); hs
[S
]=h
[S
];while(q
.size()){int t
=q
.front(); q
.pop();for(int i
=h
[t
];~i
;i
=ne
[i
]){int ver
=e
[i
];if(depth
[ver
]==-1&&w
[i
]>0){depth
[ver
]=depth
[t
]+1;hs
[ver
]=h
[ver
];if(ver
==T
) return true;q
.push(ver
);}}}return false;}int dfs(int u
,int flow
){if(u
==T
) return flow
;int d
=flow
;for(int i
=hs
[u
];~i
;i
=ne
[i
]){int ver
=e
[i
]; hs
[u
]=i
;if(depth
[ver
]==depth
[u
]+1&&w
[i
]>0){int t
=dfs(ver
,min(w
[i
],d
));if(!t
) depth
[ver
]=-1;d
-=t
; w
[i
]-=t
; w
[i
^1]+=t
;if(!d
) break;}}return flow
-d
;}LL 
dinic(){LL ans
=0,flow
;while(bfs()) while(flow
=dfs(S
,INF
)) ans
+=flow
;return ans
;}
}MF
;
vector
<int>v1
[1000010],v2
[1000101];int main()
{
scanf("%d%d%d",&n
,&m
,&k
);for(int i
=1;i
<=n
;i
++) scanf("%d",&b
[i
]);for(int i
=1;i
<=n
;i
++) scanf("%d",&c
[i
]);for(int i
=1;i
<=m
;i
++) {int a
,b
; scanf("%d%d",&a
,&b
);g
[a
][b
]=1;}for(int i
=1;i
<=n
;i
++) {v1
[b
[i
]].pb(i
);v2
[c
[i
]].pb(i
);}LL ans
=0;for(int i
=k
;i
>=1;i
--) if(v1
[i
].size()||v2
[i
].size()) {MF
.init();MF
.S
=0; MF
.T
=n
+n
+10;for(auto x
:v1
[i
]) MF
.add(0,x
,1);for(auto x
:v2
[i
]) MF
.add(x
+n
,n
+n
+10,1);for(auto x
:v1
[i
]) {for(auto y
:v2
[i
]) {if(g
[x
][y
]) {MF
.add(x
,y
+n
,1);}}}LL now
=MF
.dinic();ans
+=(1ll*v1
[i
].size()+1ll*v2
[i
].size()-now
)*i
;}printf("%lld\n",ans
);return 0;
}
                            總結
                            
                                以上是生活随笔為你收集整理的2021牛客暑期多校训练营3 C Minimum grid 网络流 + 二分图匹配的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。