BZOJ 1001 最小割转最短路,平面图转对偶图
题意:这样的图,从左上角到右下角,要把通路拦住。路径权值为拦这条路的花费,求最小花费。
tags:输入文件有10M,最大流会超时。正解是转为对偶图中最短路。 注:这个题目有个坑,n和m都有可能等于1。
两个面相邻就加一条边,最后再加一条回边,即s-t原本一个面,要分开。对偶图中每一条路径对应一条割,最短路即是最小割。这样效率要比最大流好很多。
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define FF(i,a,b) for (int i=a;i<=b;i++) #define F(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 2e3+10, M = 2e6+10; struct Edge{ int to, next, w;}e[M<<2]; int n, m, nm; int dis[M], head[M], q[M], tot; bool flag[M], fl=0; void Addedge(int u, int v, int w) { e[++tot].to=v, e[tot].w=w, e[tot].next=head[u], head[u]=tot; e[++tot].to=u, e[tot].w=w, e[tot].next=head[v], head[v]=tot; } void Readgragh() { scanf("%d %d", &n, &m); nm=(n-1)*(m-1)*2; int x; if(n==1 || m==1) { fl=1; if(n>m) swap(n,m); int ans=INF; FF(j,1,m-1) { scanf("%d", &x); ans=min(ans, x); } printf("%d\n", ans); } else { FF(j,1,m-1) scanf("%d", &x), Addedge(j*2-1, nm+1, x); FF(i,2,n-1) FF(j,1,m-1) scanf("%d", &x), Addedge(((i-2)*(m-1)+j)*2, ((i-1)*(m-1)+j)*2-1, x); FF(j,1,m-1) scanf("%d", &x), Addedge(0, ((n-2)*(m-1)+j)*2, x); FF(i,1,n-1) FF(j,1,m) { scanf("%d", &x); if(j==1) Addedge(0, ((i-1)*(m-1)+j)*2, x); else if(j==m) Addedge(((i-1)*(m-1)+j-1)*2-1, nm+1, x); else Addedge(((i-1)*(m-1)+j-1)*2-1, ((i-1)*(m-1)+j)*2, x); } FF(i,1,n-1) FF(j,1,m-1) scanf("%d", &x), Addedge(((i-1)*(m-1)+j)*2-1, ((i-1)*(m-1)+j)*2, x); } } void Spfa() { mes(dis, INF); int t=0, h=0; dis[0]=q[t++]=0, flag[0]=1; while(t!=h) { int u=q[h++]; flag[u]=0; if(h==M) h=0; for(int i=head[u]; i; i=e[i].next) { int v=e[i].to; if(dis[v]>dis[u]+e[i].w) { dis[v]=dis[u]+e[i].w; if(flag[v]==0) { flag[v]=1, q[t++]=v; if(t==M) t=0; } } } } } int main() { Readgragh(); if(fl) return 0; Spfa(); printf("%d\n", dis[nm+1]); return 0; }