zoukankan      html  css  js  c++  java
  • 【*篇】SDOI2009 最优图像

    又是一道辣鸡卡常数题….
    luogu上有些题的时限还是有毒的… 最后也只能靠O2过掉了…
    不过给我原题当时的2s我随便过给你看嘛, 哪怕评测姬慢50%都没关系的.. 贴一下codevs的截图…
    这里写图片描述
    你看最慢的点也就1.07s…… (毕竟程序自带大常数←_←

    好了不吐槽了, 我们来分析一下这道题吧…
    其实我当时做的时候(好像还是做学校食堂的那次测试?)并不知道这是一道网络流…
    然后就写暴力滚粗…

    但据说这是一种非常常见的建图方式.. 我们还是分析题目条件.
    我们在网络流里面做到的题目都是求和的, 那么我们就要想办法把Π转换为.
    转换完之后就可以跑最大费用最大流了.那么怎么转换呢?? 用对数!!!
    我们高一的时候学过,log(xy)=log x+log y(底大于0且不等于1), 这样我们就可以建边了.

    • 每一行, 每一列作为一个点, 分别放在两边.
    • 行和列之间连一条流量为1, 费用为交点的概率的对数的边, 表示这个点最多选一次, 选的话取这个概率.
    • 源点向每个行对应的点连流量为这一行的黑像素数, 费用为0的边, 表示这一行要选这么多个.
    • 每个列对应的点向汇点连流量为这一列的黑像素数, 费用为0的边, 表示这一列要选这么多个.

    样例建图大约就是这个样子(好像还并不是很清楚怎么建嘛) (对数的底我就随便取个e算了)
    这里写图片描述

    然后费用取反跑费用流就行了. 据说这个题只能用zkw过, 但我的zkw也没过

    代码:

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=205;
    const int M=23333;
    const int INF=0x7f7f7f7f;
    inline int gn(int a=0,char c=0){
        for(;c<'0'||c>'9';c=getchar());
        for(;c>47&&c<58;c=getchar())a=a*10+c-48;return a;
    }
    int v[N],nxt[M],to[M],fl[M],co[M],tot=1;
    void buildedge(int x,int y,int flow,int cost){
        to[++tot]=y; nxt[tot]=v[x]; v[x]=tot; fl[tot]=flow; co[tot]=cost;
        to[++tot]=x; nxt[tot]=v[y]; v[y]=tot; fl[tot]=0; co[tot]=-cost;
    }
    int d[N],n,m,s,t,cost,p[N][N],a[N],b[N];
    int q[M],H,T,i,j,k;
    bool vis[N];
    inline bool spfa(int s,int t){
        memset(vis,0,sizeof(vis));
        memset(d,0x7f,sizeof(d));
        d[t]=0; H=0; T=1; vis[t]=1; q[T]=t;
        while(H<T){
            int x=q[++H]; vis[x]=0;
            for(int i=v[x];i;i=nxt[i])
                if(fl[i^1]&&d[to[i]]>d[x]-co[i]){
                    d[to[i]]=d[x]-co[i];
                    if(!vis[to[i]]) vis[to[i]]=1,q[++T]=to[i];
                }
        }
        return d[s]<INF;
    }
    int dfs(int x,int mx,int s=0){ vis[x]=1;
        if(x==t) return mx; int k;
        for(int i=v[x];i;i=nxt[i])
            if(!vis[to[i]]&&fl[i]&&d[to[i]]==d[x]-co[i]){
                k=::dfs(to[i], mx-s>fl[i]?fl[i]:mx-s);
                if(k) cost+=k*co[i],fl[i]-=k,fl[i^1]+=k,s+=k;
                if(s==mx) break;
            }
        return s;
    }
    int mcmf(int flow=0){
        while(::spfa(s, t)){ vis[t]=1;
            while(vis[t]){
                memset(vis,0,sizeof(vis));
                flow+=::dfs(s, INF);
            }
        } return flow;
    }
    void findans(){
        for(int i=1;i<=n;++i)
            for(int j=v[i];j;j=nxt[j])
                if(to[j]>n)
                    p[i][to[j]-n]=!fl[j];
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j)
                putchar(48+p[i][j]);
            putchar(10);
        }
    }
    int main(){
        n=gn(); m=gn(); s=0; t=n+m+1;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j){
                int k=gn();
                if(k) ::buildedge(i, j+n, 1, (int)(-log2(k)*2333333));
            }
        for(int i=1;i<=n;++i)
            ::buildedge(s, i, gn(), 0);
        for(int i=1;i<=m;++i)
            ::buildedge(i+n, t, gn(), 0);
        mcmf(); findans();
    }

    最后, 卡常数是非常不对的一件事情…或者说我该去化验血统了?

  • 相关阅读:
    js浅拷贝和深拷贝
    使用slice和concat对数组的深拷贝和浅拷贝
    JS数组常用方法---8、concat方法
    JS数组常用方法---7、join方法
    js中将类数组转换为数组的几种方法
    JS 使用const声明常量的本质(很多人都有误解)
    JS中对象数组按照对象的某个属性进行排序
    vue源码分析参考---2、数据代理
    vue源码分析参考---1、准备工作
    ES6课程---5、形参默认值
  • 原文地址:https://www.cnblogs.com/enzymii/p/8412099.html
Copyright © 2011-2022 走看看