• P4001 [BJOI2006]狼抓兔子


    传送门

    显然是网络流最小割

    朴素的dinic会被卡

    但是如果加上玄学优化就可以过了

    主要是讲另一个方法

    可以发现每条路径是不会交错的

    对于样例的图,我们如果从右上随便走出发一条线到左下

    把线经过的边全部割掉,就是一种可行的方案

    所以可以把每个平面看成点,点之间的边就是平面之间的公共边

    只要我们从右上的一个虚节点出发,走到左下的一个虚节点

    它的长度就是把路径经过的边割掉的代价

    所以就可以跑最短路找最小代价了

    重要的是怎么把图转化

    首先把每个平面标号,然后慢慢找规律....

    具体还是看代码吧

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    inline int read()
    {
        int x=0;
        char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return x;
    }
    const int N=2e6+7;
    int fir[N],from[N<<2],to[N<<2],val[N<<2],cnt;//存转化后的图
    inline void add(int a,int b,int c)
    {
        from[++cnt]=fir[a];
        fir[a]=cnt;
        to[cnt]=b; val[cnt]=c;
    }//连边
    int n,m;
    int dis[N];
    struct node
    {
        int u,v;
        bool operator < (const node &b) const{
            return u>b.u;
        }
    };
    priority_queue <node> q;
    inline void Dijk()//最短路
    {
        memset(dis,0x7f,sizeof(dis));
        dis[0]=0;
        q.push((node){0,0});
        while(!q.empty())
        {
            int u=q.top().u,v=q.top().v; q.pop();
            if(u!=dis[v]) continue;
            for(int i=fir[v];i;i=from[i])
            {
                int x=to[i];
                if(dis[v]+val[i]<dis[x])
                {
                    dis[x]=dis[v]+val[i];
                    q.push((node){dis[x],x});
                }
            }
        }
    }
    int main()
    {
        int a,x,y;
        cin>>n>>m;
        //下面这些是可以慢慢推的...
        for(int i=1;i<=n;i++)
            for(int j=1;j<m;j++)
            {
                x=(i-2)*(m-1)*2+j*2-1; y=x+(m-1)*2+1;
                if(i==1) x=0,y=j*2;
                if(i==n) y=(n-1)*(m-1)*2+1;
                a=read();
                add(x,y,a); add(y,x,a);
            }
        for(int i=1;i<n;i++)
            for(int j=1;j<=m;j++)
            {
                x=(i-1)*(m-1)*2+j*2-1; y=x-1;
                if(j==1) y=(n-1)*(m-1)*2+1;
                if(j==m) x=0;
                a=read();
                add(x,y,a); add(y,x,a);
            }
        for(int i=1;i<n;i++)
            for(int j=1;j<m;j++)
            {
                x=(i-1)*(m-1)*2+j*2; y=x-1;
                a=read();
                add(x,y,a); add(y,x,a);
            }
        Dijk();
        printf("%d",dis[(n-1)*(m-1)*2+1]);
        return 0;
    }
  • 相关阅读:
    如何锻炼出最牛程序员的编码套路
    如果仔细观察他们,你会发现他们时时都在锻炼
    单纯地每天埋头于工作并不能算是真正意义上的锻炼
    把全世界的人们都联系在一起,提升人们的社交参与度
    HTML5十五大新特性
    html5的八大特性
    【贪心】【二维偏序】【权值分块】bzoj1691 [Usaco2007 Dec]挑剔的美食家
    【分块】【链表】bzoj2738 矩阵乘法
    【分块】bzoj3343 教主的魔法
    【线段树】bzoj3747 [POI2015]Kinoman
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9682655.html
Copyright © 2020-2023  润新知