zoukankan      html  css  js  c++  java
  • [Hnoi2013]消毒

    Description

    最近在生物实验室工作的小T遇到了大麻烦。
    由于实验室最近升级的缘故,他的分格实验皿是一个长方体,其尺寸为abc,a、b、c 均为正整数。为了实验的方便,它被划分为abc个单位立方体区域,每个单位立方体尺寸
    为111。用(i,j,k)标识一个单位立方体,1 ≤i≤a,1≤j≤b,1≤k≤c。这个实验皿已经很久没有人用了,现在,小T被导师要求将其中一些单位立方体区域进 行消毒操作(每个区域可以被重复消毒)。而由于严格的实验要求,他被要求使用一种特定 的F试剂来进行消毒。 这种F试剂特别奇怪,每次对尺寸为xyz的长方体区域(它由xyz个单位立方体组 成)进行消毒时,只需要使用min{x,y,z}单位的F试剂。F试剂的价格不菲,这可难倒了小 T。现在请你告诉他,最少要用多少单位的F试剂。(注:min{x,y,z}表示x、y、z中的最小 者。)

    Input

    第一行是一个正整数D,表示数据组数。接下来是D组数据,每组数据开头是三个数a,b,c表示实验皿的尺寸。接下来会出现a个b 行c列的用空格隔开的01矩阵,0表示对应的单位立方体不要求消毒,1表示对应的单位立方体需要消毒;例如,如果第1个01矩阵的第2行第3列为1,则表示单位立方体(1,2,3)需要被消毒。输入保证满足abc≤5000,T≤3。

    Output

    仅包含D行,每行一个整数,表示对应实验皿最少要用多少单位 的F试剂。

    Sample Input

    1
    4 4 4
    1 0 1 1
    0 0 1 1
    0 0 0 0
    0 0 0 0
    0 0 1 1
    1 0 1 1
    0 0 0 0
    0 0 0 0
    0 0 0 0
    0 0 0 0
    1 0 0 0
    0 0 0 0
    0 0 0 0
    0 0 0 0
    0 0 0 0
    1 0 0 0

    Sample Output

    3

    HINT

    对于区域(1,1,3)-(2,2,4)和(1,1,1)-(4,4,1)消毒,分别花费2个单位和1个单位的F试剂。2017.5.26新加两组数据By Leoly,未重测.

    Solution

    洛谷的评测机有伟大的神力。。。。

    对于这个题,有一种鬼畜的伪证,至于是什么不想说了。。。

    首先我们可以证明我们一次一定是要消掉一个面的,也就是消除的部分中的{x,y,z}里面一定有一个是1,其他两个撑到最大,因为这样可以保证最优。

    那么我们现在可以继续看这道题了。首先考虑这样一个算法,假设这个题目的要求变成在一个二维平面上搞,那么明显,我们把每行每列当做点,把格子里是否有数变成边,不难看出我们现在就是要求这个题的最小覆盖集,那么没的说了,一个最大流随便就过了。

    然后我们开始考虑三维的,明显的是,没有三分图匹配这种鬼畜的算法,那么怎么办呢?

    题目中有这样一个条件,(a imes b imes cle 5000)。随便开一下根可以发现,这仨数里面肯定有一个比17要小,那么就可以搞搞事情了,我们可以把这个立方体最小的那条边当成高,然后枚举删掉哪一层,把没有删去的层拍扁到一个二维平面上,那么就可以在这个新的二维平面上搞搞二分图匹配什么的了。

    那么我们是不是就轻松A掉了这个题?

    Code1

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <iostream>
    #include <cstdlib>
    #include <cmath>
    #include <string>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <set>
    #define re register
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define pos(i,j,l) ((i-1)*b*c+(j-1)*c+l)
    #define MAXN 5005
    #define MAXM 15011
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    #define ms(arr) memset(arr, 0, sizeof(arr))
    const int inf = 0x3f3f3f3f;
    int n,s,t,cur[MAXN],m;
    int d[5005],cut[20],a,b,c,cost,minn=100,cnt;
    int sx[4][5005];
    struct po
    {
        int nxt,to,w;
    }edge[MAXM];
    int head[MAXN],dep[MAXN],num=-1;
    inline int read()
    {
        int x=0,c=1;
        char ch=' ';
        while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
        while(ch=='-') c*=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
        return x*c;
    }
    inline void add_edge(int from,int to,int w)
    {
        edge[++num].nxt=head[from];
        edge[num].to=to;
        edge[num].w=w;
        head[from]=num;
    }
    inline void add(int from,int to,int w)
    {
        add_edge(from,to,w);
        add_edge(to,from,0);
    }
    inline bool bfs()
    {
        for(re int i=s;i<=t;i++)dep[i]=0;
        queue<int> q;
        while(!q.empty())
        q.pop();
        q.push(s);
        dep[s]=1;
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(re int i=head[u];i!=-1;i=edge[i].nxt)
            {
                int v=edge[i].to;
                if(dep[v]==0&&edge[i].w>0)
                {
                    dep[v]=dep[u]+1;
                    if(v==t) return 1;
                    q.push(v);
                }
            }
        }
        return 0;
    }
    inline int dfs(int u,int dis)
    {
        if(u==t)
        return dis;
        int diss=0;
        for(re int& i=cur[u];i!=-1;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(edge[i].w!=0&&dep[v]==dep[u]+1)
            {
                int check=dfs(v,min(dis,edge[i].w));
                if(check!=0)
                {
                    dis-=check;
                    diss+=check;
                    edge[i].w-=check;
                    edge[i^1].w+=check;
                    if(dis==0) break;
                }
            }
        }
        return diss;
    }
    inline int dinic()
    {
        int ans=0;
        while(bfs())
        {
            for(re int i=0;i<=t;i++)
            cur[i]=head[i];
            while(int d=dfs(s,inf))
            ans+=d;
        }
        return ans;
    }
    inline void get_cut(int x)
    {
        memset(cut,0,sizeof(cut));
        for(re int i=0;i<a;i++){
            if(x&(1<<i)) cut[i+1]=1,cost++;
        }
    }
    inline void build()
    {
        for(re int i=1;i<=b;i++)
            add(s,i,1);
        for(re int i=1;i<=c;i++)
            add(i+b,t,1);
    }
    inline void prepare()
    {
        for(re int i=s;i<=t;i++) head[i]=-1;
        num=-1;
    }
    inline void copy()
    {
        for(re int i=1;i<=cnt;i++)
            if(!cut[sx[1][i]])
                add(sx[2][i],sx[3][i]+b,1);
    }
    int main()
    {
        int T=read();
        while(T--){
            a=read();b=read();c=read();
            int minx=min(a,min(b,c));
            memset(sx,0,sizeof(sx));
            cnt=0;
            for(re int i=1;i<=a;i++)
                for(re int j=1;j<=b;j++)
                    for(re int l=1;l<=c;l++){
                        int x=read();
                        if(!x) continue;
                        sx[1][++cnt]=i;
                        sx[2][cnt]=j;
                        sx[3][cnt]=l;
                    }
            if(minx==b) swap(a,b),swap(sx[1],sx[2]);
            else if(minx==c) swap(a,c),swap(sx[1],sx[3]);
            s=0,t=b+c+1;
            for(re int i=0;i<1<<a;i++){
                cost=0;
                get_cut(i);
                if(cost>minn) continue;
                prepare();
                copy();
                build();
                cost+=dinic();
                minn=min(minn,cost);
            }
            cout<<minn<<endl;
            minn=100;
        }
    }
    
    

    But

    看到这个Code不同寻常了吧,这个代码在洛谷上开着O2A掉了,然后令人惊奇的是,它过不了我自己手造的随机数据。。然后我把gay的比我快10倍的代码拿过来测了测,照样过不了。。。。然后发现把图拍扁的时候这个效率有可能退化为(a*b*c)的鬼畜效率,光这个就T掉了。。。。然后。。。看了下题解第一个,发现是一遍DFS一遍重新构造图。。然后,没有然后了。

    Code2

    额,题解代码,我自己的改来改去太丑了,仔细看看那个搜索过程,

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    inline int read() {
        int res = 0; bool bo = 0; char c;
        while (((c = getchar()) < '0' || c > '9') && c != '-');
        if (c == '-') bo = 1; else res = c - 48;
        while ((c = getchar()) >= '0' && c <= '9')
            res = (res << 3) + (res << 1) + (c - 48);
        return bo ? ~res + 1 : res;
    }
    const int N = 5005, E = 23, INF = 0x3f3f3f3f;
    int n, D[5], pos, ecnt, nxt[N], adj[N], go[N], val[N], my[N],
    X[N][5], Ans, cnt, vis[N], times;
    bool sel[E];
    void add_edge(int u, int v, int w) {
        nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;
    }
    bool dfs(int u) {
        for (int e = adj[u], v; e; e = nxt[e])
            if (!sel[val[e]] && vis[v = go[e]] < times) {
                vis[v] = times;
                if (!my[v] || dfs(my[v])) {
                    my[v] = u;
                    return 1;
                }
            }
        return 0;
    }
    int solve(int tt) {
        int i, j, ans = 0;
        for (i = 1; i <= cnt; i++) my[i] = 0;
        for (i = 1; i <= cnt; i++) {
            times++;
            if (dfs(i)) ans++;
            if (tt + ans >= Ans) return tt + ans;
        }
        return tt + ans;
    }
    void Dfs(int dep, int tt) {
        if (dep > D[pos]) return (void) (Ans = min(Ans, solve(tt)));
        sel[dep] = 1; Dfs(dep + 1, tt + 1);
        sel[dep] = 0; Dfs(dep + 1, tt);
    }
    void work() {
        int i, j, k, x; n = 0; Ans = INF; cnt = 0;
        pos = 1; D[1] = read(); D[2] = read(); D[3] = read();
        if (D[2] < D[pos]) pos = 2; if (D[3] < D[pos]) pos = 3;
        for (i = 1; i <= 3; i++) if (i != pos) cnt = max(cnt, D[i]);
        for (i = 1; i <= D[1]; i++) for (j = 1; j <= D[2]; j++)
        for (k = 1; k <= D[3]; k++) {
            x = read(); if (x) X[++n][1] = i, X[n][2] = j, X[n][3] = k;
        }
        ecnt = 0; for (i = 1; i <= cnt; i++) adj[i] = 0;
        for (i = 1; i <= n; i++) {
            if (pos == 1) add_edge(X[i][2], X[i][3], X[i][1]);
            else if (pos == 2) add_edge(X[i][1], X[i][3], X[i][2]);
            else add_edge(X[i][1], X[i][2], X[i][3]);
        }
        printf("%d
    ", (Dfs(1, 0), Ans));
    }
    int main() {
        int T = read();
        while (T--) work();
        return 0;
    }
    
  • 相关阅读:
    deeplearning.ai 卷积神经网络 Week 1 卷积神经网络
    deeplearning.ai 构建机器学习项目 Week 2 机器学习策略 II
    deeplearning.ai 构建机器学习项目 Week 1 机器学习策略 I
    deeplearning.ai 改善深层神经网络 week3 超参数调试、Batch Normalization和程序框架
    deeplearning.ai 改善深层神经网络 week2 优化算法
    deeplearning.ai 改善深层神经网络 week1 深度学习的实用层面
    cs231n spring 2017 lecture8 Deep Learning Networks
    cs231n spring 2017 lecture7 Training Neural Networks II
    cs231n spring 2017 lecture6 Training Neural Networks I
    cs231n spring 2017 Python/Numpy基础
  • 原文地址:https://www.cnblogs.com/victorique/p/9042473.html
Copyright © 2011-2022 走看看