开坑!
1001: [BeiJing2006]狼抓兔子
思路:平面图最小割
Orz周冬,主要思想都在他的文章《浅析最大最小定理在信息学竞赛中的应用》中提到
显然最大流不现实
将整个图从斜线切开,分为两块
若我们将每一块区域看成一个点,两块区域的公共边作为这两点的连边
显然,从左下到右上的最短路就是整个图的最小割
真是神思想!
代码:
我这个人比较喜欢手写优先队列……
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define rint register int
#define ull unsigned long long
using namespace std;
const int MAXN=2*1000*1000+10,MAXM=6*1000*1000+10;
int n,m;
int s,t;
#define heng(a,b) ((a-1)*2-(1-b))*(m-1)
#define inf 1<<30
int frontx[MAXM],fronty[MAXM],frontk[MAXM];
int stdx[MAXN],orderx[MAXM];
int nn,mm;
void add(int x,int y,int k)
{
if (x!=t) { frontx[++mm]=x; fronty[mm]=y; frontk[mm]=k; }
if (y!=s) { frontx[++mm]=y; fronty[mm]=x; frontk[mm]=k; }
return ;
}
int num[MAXN];
void Read(int &k)
{
char c=getchar(); k=0;
while (c<'0' || c>'9') c=getchar();
while (c>='0' && c<='9') {
k=k*10+c-'0';
c=getchar(); }
return ;
}
void sortx()
{
for (rint i=1;i<=mm;i++)
num[frontx[i]]++;
for (rint i=1;i<=nn;i++) {
num[i]+=num[i-1];
stdx[i]=num[i]; }
for (rint i=1;i<=mm;i++)
orderx[++num[frontx[i]-1]]=i;
return ;
}
struct Heap
{
unsigned int dis;
int x;
}heap[MAXN];
bool operator < (Heap A,Heap B) { return A.dis<B.dis; }
int point[MAXN];
void adjustup(int x)
{
static bool next;
next=true;
while (next) {
next=false;
static int f;
f=x/2;
if (f)
if (heap[x]<heap[f]) {
swap(heap[x],heap[f]);
point[heap[x].x]=x; point[heap[f].x]=f;
x=f; next=true; }}
return ;
}
void change(int l,int r)
{
swap(heap[l],heap[r]);
point[heap[r].x]=r; point[heap[l].x]=l;
return ;
}
void adjustdown(int x)
{
static bool next;
next=true;
while (next) {
next=false;
static int l,r;
l=x*2,r=x*2+1;
if (l<=nn)
if (r<=nn) {
if (heap[l]<heap[r] && heap[l]<heap[x]) {
change(l,x);
x=l; next=true; }
else if (heap[r]<heap[x]) {
change(r,x);
x=r; next=true; }
else if (heap[l]<heap[x]) {
change(l,x);
x=l; next=true; }}}
return ;
}
void dijsktra()
{
for (rint i=1;i<=nn;i++) {
heap[i].dis=inf;
point[i]=heap[i].x=i; }
heap[s].dis=0;
adjustup(s);
while (nn) {
static Heap now;
now=heap[1];
if (now.x==t) {
cout<<heap[point[t]].dis<<endl;
return ; }
change(1,nn);
nn--; adjustdown(1);
static int x;
x=now.x;
for (rint i=stdx[x-1]+1;i<=stdx[x];i++) {
static int next;
next=fronty[orderx[i]];
if (heap[point[next]].dis>now.dis+frontk[orderx[i]]) {
heap[point[next]].dis=now.dis+frontk[orderx[i]];
adjustup(point[next]); }}}
return ;
}
void init()
{
Read(n); Read(m);
if (n==1 || m==1) {
int nn=n,ans=inf;
if (nn==1) nn=m;
for (int k,i=1;i<nn;i++) {
Read(k);
ans=min(ans,k); }
if (ans==inf)
cout<<0<<endl;
else
cout<<ans<<endl;
return ; }
s=(n-1)*(m-1)*2+1,t=(n-1)*(m-1)*2+2;
nn=t;
for (rint i=1;i<=n;i++)
for (rint k,j=1;j<m;j++) {
Read(k);
if (i==1) add(s,heng(i,1)+j,k);
else if (i==n) add(heng(i,0)+j,t,k);
else add(heng(i,0)+j,heng(i,1)+j,k); }
for (rint i=1;i<n;i++)
for (rint k,j=1;j<=m;j++) {
Read(k);
if (j==1) add(t,heng(i+1,0)+j,k);
else if (j==m) add(s,heng(i,1)+j-1,k);
else add(heng(i,1)+j-1,heng(i+1,0)+j,k); }
for (rint i=1;i<n;i++)
for (rint k,j=1;j<m;j++) {
Read(k);
add(heng(i,1)+j,heng(i+1,0)+j,k); }
sortx();
dijsktra();
return ;
}
int main()
{
init();
return 0;
}