推薦文章:《淺析最大最小定理在信息學競賽中的應用》--周冬


講這部分之前,請先閱讀以上的文章(講得十分好%%%)(當然閱讀到27頁就好了)
讀完後,我們發現這道題完全可以用其對偶圖來跑最短路。
原圖 對偶圖
面數 x 面數 y
點數 y 那麼其對偶圖中 點數 x
邊數 z 邊數 z
面數和點數正好相反。
將原圖的起點和終點連接起來,建立一個新的面(這是必須的)。

當然s點和t點之間是沒有邊的。
s和1,7,9,11之間有邊。
t和2,4,6,12之間有邊。
上面是我們建好的對偶圖,從左至右依次編號,關於對偶圖中面的編號,因為我們是按照橫邊,縱邊,斜邊的順序讀入的,所以我們一定要按照一定的方法對這些圖編號
我采用的是從左至右依次編號,因為我們可以很清楚當前邊連接的兩個點(原圖中的兩個面)所在的位置,因為這是平面圖,所以可以用歐拉公式來求出之前有多少點(
原圖中的面)。再加上這個點(原圖中的面(重要的事說三遍))在當前行中的位置就是它的編號。
只要原圖中的兩個面之間存在邊,那麼它的對偶圖中的兩個點就存在邊。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int cnt, i, j, x, xx, xxx, h, t, s, hh[2010000], n, m, w;
bool dd[2010000];
int e, l[2010000], d[1010000], hhh, ww;
struct node
{
int v, next, z;
} b[6010000];
inline void add(int aa, int bb, int cc)//鄰接表,建雙向邊
{
b[++cnt].v = bb;
b[cnt].next = hh[aa];
b[cnt].z = cc;
hh[aa] = cnt;
b[++cnt].v = aa;
b[cnt].next = hh[bb];
b[cnt].z = cc;
hh[bb] = cnt;
}
void add1()
{
for(i = 1; i < m; ++i)
{
scanf("%d", &x);
add(i * 2, t, x);
}
for(i = 2; i < n; ++i)
{
for(j = 1; j < m; ++j)
{
scanf("%d", &x);
add((i - 1) * (m - 1) * 2 + j * 2, (i - 1) * (m - 1) * 2 + j * 2 - m * 2 + 1, x);//利用歐拉公式確定編號並建邊(下面的add函數也是如此)
}
}
for(j = 1; j < m; ++j)
{
scanf("%d", &x);
add(s, (n - 2) * 2 * (m - 1) + j * 2 - 1, x);
}
}
void add2()
{
for(i = 1; i < n; ++i)
{
scanf("%d", &x);
xx = (i - 1) * (m - 1) * 2 + 1;
add(s, xx, x);
for(j = 2; j < m; ++j)
{
scanf("%d", &x);
xx += 2;
add(xx - 1, xx, x);
}
scanf("%d", &x);
add(xx + 1, t, x);
}
}
inline void add3()
{
for(i = 1; i < n; ++i)
{
for(j = 1; j < m; ++j)
{
scanf("%d", &x);
add((i - 1) * (m - 1) * 2 + j * 2, (i - 1) * (m - 1) * 2 + j * 2 - 1, x);
}
}
}
//下面的spfa中一定要用循環隊列,省空間。不用的話空間開小(這很有可能畢竟1百萬個點)可能會被卡。
void spfa()
{
dd[s] = true;
h = 0;
w = 0;
memset(l,0x3f,sizeof(l));//將l數組賦成最大值
//hhh記錄的是我們用的是隊列中第幾個元素(實際上)
//ww記錄的是隊列中總共有幾個元素
l[s] = 0;
while(1)
{
if(hhh > ww)break;
h = hhh % 1000001;
w = ww % 1000001;
for(i = hh[s]; i; i = b[i].next)
{
e = b[i].v;
if(l[s] + b[i].z < l[e])
{
l[e] = l[s] + b[i].z;
if(!dd[e])w = ww % 1000000, d[++w] = e, ww++, dd[e] = true;
}
}
dd[s] = false;
h = hhh % 1000000;
s = d[++h];
hhh++;
}
}
int main()
{
scanf("%d %d", &n, &m);
if(n == m && n == 1)//特判
{
printf("0");
return 0;
}
s = 0;
t = 2 * (n - 1) * (m - 1) + 1;
add1();//讀入橫邊
add2();//讀入縱邊
add3();//讀入斜邊
spfa();//對其對偶圖求s————t的最短路
printf("%d", l[t]);
return 0;
}