BZOJ 1001 (UVa1376, LA3661 ) - 平面图最大流(对偶图 -> 最短路)
直接套Dinic妥妥地TLE。。怎么办呢。。
这是一个平面图。。有一些很好玩的性质。。
利用这些性质,我们可以做一些奇妙的转化,把流量转化为边的长度,然后跑一遍最短路即可。。
这个转化,就是对偶图。。
理论依据详见2008年国家集训队周冬的论文《两极相通——浅析最大—最小定理在信息学竞赛中的应用》、
然后又发现白书上居然有这道题。。UVa1376 ( LA3661 ),白书上的解释更加通俗感性。。
考虑平面图给人的直观感受,那就是必须要从“中间”“连续地”割断。更具体地说,就从左/下连到右/上即可。
那么既然要是连续的,就不难联想到最短路问题。把每条路径当作一个点,那么一个割就变成了一条路径,一张边权图就变成了一张点权图。
Dijkstra的初始化怎么做呢?直接令所有下边和右边的d值为0即可。
注意建图时点标号的构造方法。
<span style="font-size:12px;">// BZOJ 1001 #include <cstdio> #include <iostream> #include <cstring> #include <queue> #include <algorithm> using namespace std; typedef long long LL; typedef unsigned long long uLL; const int N=2000000+5, M=4*N, INF=0x3f3f3f3f; #define rep(i,a,b) for (int i=a; i<=b; i++) #define uep(i,a,b) for (unsigned i=a; i<b; i++) #define dep(i,a,b) for (int i=a; i>=b; i--) #define read(x) scanf("%d", &x) #define fill(a,x) memset(a, x, sizeof(a)) struct Graph { int s, from[M], to[M], dis[M], pre[M], last[N]; void init() { s=-1; fill(last, -1); } void ine(int a, int b, int d) { s++; from[s]=a, to[s]=b, dis[s]=d, pre[s]=last[a]; last[a]=s; } void ine2(int a, int b, int d) { ine(a, b, d); ine(b, a, d); } } G; #define reg(i,s,u) for (int i=s.last[u]; i!=-1; i=s.pre[i]) struct Node { int id, dis; Node(int id_, int dis_) { id=id_, dis=dis_; } bool operator < (const Node &x) const { return dis>x.dis; } }; int n, m, nm, w, d[N]; bool done[N]; priority_queue<Node> pQ; void Dijkstra(int s) { rep(i,0,nm+1) d[i]=INF, done[i]=false; d[s]=0; pQ.push(Node(s,0)); while (!pQ.empty()) { Node Nx=pQ.top(); pQ.pop(); int x=Nx.id; if (done[x]) continue; done[x]=true; reg(i,G,x) { int y=G.to[i], w=G.dis[i]; if (done[y]) continue; if (d[x]+w<d[y]) { d[y]=d[x]+w; pQ.push(Node(y, d[y])); } } } } int main() { read(n); read(m); G.init(); // 千万别忘了初始化! nm=(n*m-m-n+1)<<1; // 所有边->的数目 rep(j,1,m-1) read(w), G.ine2(j, nm+1, w); // 第一行的横边与S(即nm+1)相连,后同理 rep(i,1,n-2) rep(j,1,m-1) read(w), G.ine2((i<<1)*(m-1)+j, ((i<<1)-1)*(m-1)+j, w); rep(j,1,m-1) read(w), G.ine2(0, ((n<<1)-3)*(m-1)+j, w); rep(i,0,n-2) rep(j,1,m) { read(w); if (j==1) G.ine2(0, (i<<1)*(m-1)+m, w); else if (j==m) G.ine2((i<<1|1)*(m-1), nm+1, w); else G.ine2((i<<1)*(m-1)+j-1, (i<<1)*(m-1)+j+m-1, w); } rep(i,0,n-2) rep(j,1,m-1) read(w), G.ine2((i<<1|1)*(m-1)+j, (i<<1)*(m-1)+j, w); Dijkstra(0); printf("%d\n", d[nm+1]); return 0; } </span>