2200专项:D. Sonya and Matrix(stl容器的内存占用问题)

原题: http://codeforces.com/problemset/problem/1004/D

题意:

有一个矩阵n*m,其中有一个位置为0,其他位置的数为到这个0的曼哈顿距离。现在题目只给出这n*m个数,问你是否可以重构出这个矩阵。如果可以,求出n*m以及0的位置。

解析:

想法其实很简单,从0往外延,下一层(第1层)正常情况下会有4个1。如果没有,则说明有几条边以及到达边界。这个时候dfs枚举每种情况,dfs的时候维护一下set即可。

说说set的维护问题。如果每次都copy一份set空间会不够,所以用引用类型传递set。所以那些删除的值在dfs完后需要恢复。

我开始是用queue来存的,寻思着不管到了哪一步,之前和现在的queue内的数加上set里的数刚好等于n*m,应该不会炸内存吧。

但是搜了一下,stl容器在压入数后会动态开辟空间,但是弹出后这部分空间并不会释放。所以这里改成了vector来存,在用完后调用v.shrink_to_fit()将空间释放(这个函数是将vector中没有存放东西的空间释放,原理是新建一个vector,将原来的导入,再删掉原来的那个)。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repp(i,b,a) for(int i=b;i>=a;i--)
#define de(v) printf("erase %d\n",v)
int ansl,ansr,ansu,ansd;

unordered_multiset<int>S;
unordered_multiset<int>::iterator it;
inline restore(vector<int>&Q){
    for(int i=0;i<Q.size();i++)S.insert(Q[i]);
    Q.shrink_to_fit();
}
bool dfs(int l,int r,int u,int d,int have,int lev){
    vector<int>Q;
    // 删除上一层外边框
    lev--;
    if(l>8e8){
        rep(i,1,min(u-1,lev)){it=S.find(i+lev);if(it==S.end()){restore(Q);return 0;}else S.erase(S.find(i+lev)),Q.push_back(i+lev);}
        rep(i,1,min(d-1,lev)){it=S.find(i+lev);if(it==S.end()){restore(Q);return 0;}else S.erase(S.find(i+lev)),Q.push_back(i+lev);}
    }
    if(r>8e8){
        rep(i,1,min(u-1,lev)){it=S.find(i+lev);if(it==S.end()){restore(Q);return 0;}else S.erase(S.find(i+lev)),Q.push_back(i+lev);}
        rep(i,1,min(d-1,lev)){it=S.find(i+lev);if(it==S.end()){restore(Q);return 0;}else S.erase(S.find(i+lev)),Q.push_back(i+lev);}
    }
    if(u>8e8){
        rep(i,1,min(l-1,lev-1)){it=S.find(i+lev);if(it==S.end()){restore(Q);return 0;}else S.erase(S.find(i+lev)),Q.push_back(i+lev);}
        rep(i,1,min(r-1,lev-1)){it=S.find(i+lev);if(it==S.end()){restore(Q);return 0;}else S.erase(S.find(i+lev)),Q.push_back(i+lev);}
    }
    if(d>8e8){
        rep(i,1,min(l-1,lev-1)){it=S.find(i+lev);if(it==S.end()){restore(Q);return 0;}else S.erase(S.find(i+lev)),Q.push_back(i+lev);}
        rep(i,1,min(r-1,lev-1)){it=S.find(i+lev);if(it==S.end()){restore(Q);return 0;}else S.erase(S.find(i+lev)),Q.push_back(i+lev);}
    }
    if(S.empty()){
        lev++;
        if(l>8e8)l=lev;
        if(r>8e8)r=lev;
        if(u>8e8)u=lev;
        if(d>8e8)d=lev;
        ansl=l,ansr=r,ansu=u,ansd=d;
        return 1;
    }
    else if(have==4){ //到边框了但是还有元素
        restore(Q);
        return 0;
    }
    lev++;


    int ct=0;
    for(it=S.find(lev);it!=S.end();it=S.find(lev)){
        ct++;Q.push_back(*it);
        S.erase(it);
    }
    if(have+ct>4){restore(Q);return 0;}
    int sta=0;if(l<8e8)sta+=1;if(r<8e8)sta+=2;if(u<8e8)sta+=4;if(d<8e8)sta+=8;

    rep(i,0,15){
        if(__builtin_popcount(i)!=4-have-ct||(i&sta))continue;
    	//剪枝
        if(have==0&&(i==2||i==4||i==8))continue;
        if(have==0&&__builtin_popcount(i)==2&&!(i==3||i==5))continue;
        if(have==0&&__builtin_popcount(i)==3&&!(i==7))continue;
        int a[4]={l,r,u,d};
        if(i&1)a[0]=lev;// 改变边框为lev(最大延到lev-1)
        if(i&2)a[1]=lev;
        if(i&4)a[2]=lev;
        if(i&8)a[3]=lev;
        if(dfs(a[0],a[1],a[2],a[3],4-ct,lev+1))return 1;
    }
    restore(Q);
    return 0;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,tmp;cin>>n;
    rep(i,1,n){
        cin>>tmp,S.insert(tmp);
    }

    if(S.find(0)==S.end()){cout<<-1<<endl;return 0;}
    S.erase(S.find(0));
    if(!dfs(1e9,1e9,1e9,1e9,0,1))cout<<-1<<endl;
    else{
        cout<<ansu+ansd-1<<' '<<ansl+ansr-1<<endl;
        cout<<ansu<<' '<<ansl<<endl;
    }
}

上一篇:保存神经网络或只保存神经网络参数


下一篇:Codeforces 1028E Restore Array 构造