• 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
    ", 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
    ", dis[nm+1]);
    
        return 0;
    }
    View Code
  • 相关阅读:
    解决后退网页已过期或刷新询问是否重新提交表单的问题
    一行代码获取中文星期
    单例模式弹出窗体实现
    JAVA实现冒泡排序
    关于BufferedWriter.write超过30W条数据写入过慢问题。
    Ibatis的简单介绍
    链接注入(便于跨站请求伪造)(AppScan扫描结果)
    会话标识未更新(AppScan扫描结果)
    跨站点脚本编制实例(AppScan扫描结果)
    深入Java核心 Java内存分配原理精讲
  • 原文地址:https://www.cnblogs.com/sbfhy/p/6402258.html
Copyright © 2020-2023  润新知