BZOJ 1001 最小割转最短路,平面图转对偶图

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;
}
View Code
posted @ 2017-02-15 17:11  v9fly  阅读(820)  评论(0编辑  收藏  举报