[BZOJ1001]BJOI2006狼抓兔子
建图建不出来啊…
目录
网络流做法
显然是一个最小割模型,让后暴力建图暴力跑最大流即可,注意原图是无向图,所以算上反边每条边实际上要连4次!(代码写的不丑的话是可以卡过的)
最小割转最短路
- 观察到这题点数边数明显不是跑网络流的数据,我们需要转化一下!
- 对偶图应用具体请参考周冬2008年集训队论文,这里只简单讲一下对于该题的应用。
- 我们从最小割做法考虑,所谓最小割就是将原图割断某些边是点分属s所在集合或t所在集合这两个连通块,其中代价就是割断的边的边权之和。
- 所以,我们考虑构建对偶图,即每一个环围成的区域在对偶图中变成了一个点,对偶图中的点与点之间连一条边,割断原图的边,并且对偶图的边边权与原图中被割断的边的边权相等。
- 对于最外层没有被割断的边,我们连一条s-t的“虚边”,将外面的区域分为两部分,外层的点向s/t连边即可。
- 这样显然,在对偶图上跑s-t的最短路,就是原图的最小割了!而且时空复杂度都降了不少!
代码
建图时一定要对对偶图的点有系统性的标号,不然要炸啊…
#include <cstdio>
#include <queue>
#include <utility>
#include <climits>
#include <algorithm>
#include <vector>
#include <functional>
using std::priority_queue;
using std::pair;
using std::min;
using std::swap;
using std::vector;
using std::greater;
const int MAXN=2e6+5,MAXM=6e6+5;
int n,m,s,t,ans;
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > hp;
struct node{
int he,dis;
bool use;
node(){dis=INT_MAX;}
}d[MAXN];
struct line{int to,nex,w;}ed[MAXM];
inline void addE(int u,int v,int w){
static int cnt=0;
ed[++cnt]=(line){v,d[u].he,w};
d[u].he=cnt;
}
inline void Dijsktra(){
d[0].dis=0;
hp.push(pair<int,int>(d[0].dis,0));
pair<int,int> tmp;
while(hp.size()){
tmp=hp.top();
hp.pop();
if(d[tmp.second].use)
continue;
d[tmp.second].use=true;
for(int i=d[tmp.second].he,v,w;i;i=ed[i].nex){
v=ed[i].to,w=ed[i].w;
if(d[tmp.second].dis+w<d[v].dis){
d[v].dis=d[tmp.second].dis+w;
hp.push(pair<int,int>(d[v].dis,v));
}
}
}
}
/*
|-----|-----|-----|-----|
| 1\ 2| 3\ 4| 5\ 6| 7\ 8|
| 9\10|11\12|13\14|15\16|
|17\18|19\20|21\22|23\24|
|-----|-----|-----|-----|
*/
inline void build(){
t=(((n-1)*(m-1))<<1)|1;
for(int i=1,u,w;i<m;++i){
scanf("%d",&w);
u=i<<1;
addE(u,t,w),addE(t,u,w);
}
for(int i=2;i<n;++i){
for(int j=1,u,v,w;j<m;++j){
scanf("%d",&w);
u=(((i-2)*(m-1)+j)<<1)-1;
v=((i-1)*(m-1)+j)<<1;
addE(u,v,w),addE(v,u,w);
}
}
for(int i=1,u,w;i<m;++i){
scanf("%d",&w);
u=(((n-2)*(m-1)+i)<<1)-1;
addE(u,s,w),addE(s,u,w);
}
for(int i=1;i<n;++i){
for(int j=1,u,v,w;j<=m;++j){
scanf("%d",&w);
if(j==1){
u=(((i-1)*(m-1)+j)<<1)-1;
addE(u,s,w),addE(s,u,w);
}
else if(j==m){
u=((i-1)*(m-1)+j-1)<<1;
addE(u,t,w),addE(t,u,w);
}
else{
u=((i-1)*(m-1)+j-1)<<1;
v=u+1;
addE(u,v,w),addE(v,u,w);
}
}
}
for(int i=1;i<n;++i){
for(int j=1,u,v,w;j<m;++j){
scanf("%d",&w);
u=(((i-1)*(m-1)+j)<<1)-1;
v=u+1;
addE(u,v,w),addE(v,u,w);
}
}
}
int main(){
scanf("%d%d",&n,&m);
if(n==1 || m==1){
ans=INT_MAX;
if(n>m) swap(n,m);
for(int i=1,w;i<=m;++i){
scanf("%d",&w);
ans=min(ans,w);
}
printf("%d",ans);
}
else{
build();
Dijsktra();
printf("%d",d[t].dis);
}
return 0;
}