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;
}
}
标签:2200,restore,return,Matrix,stl,rep,erase,lev,find 来源: https://blog.csdn.net/jk_chen_acmer/article/details/89279868