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;
    }
    
  • 相关阅读:
    String为值类型还是引用类型
    Mat数据类型
    各数据类型取值范围和所占字节数
    opencv matType
    python函数参数中冒号与箭头
    批量删除list中元素的方法
    PyQt QListview和QListWidgt
    函数形参中的冒号与箭头
    CSS选择器之相邻兄弟选择器
    CSS选择器之子元素选择器
  • 原文地址:https://www.cnblogs.com/victorique/p/9042473.html
Copyright © 2011-2022 走看看