题解 邻面合并
考场上有个贪心思路,hack不掉自己就写了,结果开场一个多小时后拍出来一组数据把自己hack了……
至于正解:
\(m\leqslant 8\),显然状压
但问题在于仅知道上一行的0/1状态并不足以对这一行进行转移,我们还要知道上一行的矩形状态
于是考虑用01状态记录上一行的划分状态
转移考虑枚举当前行的划分状态,计算出需要新增加多少矩形
可以用当前行的矩形个数减去上一行与这一行划分状态相同的矩形个数
一个判断方法是考虑若这个矩形与上一行的矩形若开头形成了匹配,则它们完全匹配的一个合法结尾是什么样的
复杂度 \(O(n^22^n)\)
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define fir first
#define sec second
#define make make_pair
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
bool mp[110][10];
namespace force{
int ans=INF;
bool all(int x1, int y1, int x2, int y2) {
for (int i=x1; i<=x2; ++i)
for (int j=y1; j<=y2; ++j)
if (!mp[i][j]) return 0;
return 1;
}
bool any(int x1, int y1, int x2, int y2) {
for (int i=x1; i<=x2; ++i)
for (int j=y1; j<=y2; ++j)
if (mp[i][j]) return 1;
return 0;
}
void cover(int x1, int y1, int x2, int y2, int val) {
for (int i=x1; i<=x2; ++i)
for (int j=y1; j<=y2; ++j)
mp[i][j]=val;
}
void dfs(int u) {
if (u>ans) return ;
if (!any(1, 1, n, m)) {ans=min(ans, u-1); return ;}
for (int i=1; i<=n; ++i) {
for (int j=1; j<=m; ++j) if (mp[i][j]) {
for (int k=i; k<=n; ++k) {
for (int h=j; h<=m; ++h) {
if (all(i, j, k, h)) {
cover(i, j, k, h, 0);
dfs(u+1);
cover(i, j, k, h, 1);
}
else break;
}
}
}
}
}
void solve() {
dfs(1);
printf("%d\n", ans);
exit(0);
}
}
namespace task1{
int top, ttop, ans;
pair<int, int> sta[N], tem[N];
deque<pair<int, int>> q;
void solve() {
pair<int, int> u;
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
// cout<<"top: "<<top<<endl;
// cout<<"sta: "; for (int j=1; j<=top; ++j) cout<<sta[j].fir<<','<<sta[j].sec<<' '; cout<<endl;
int lst=0;
for (int j=1; j<=m+1; ++j) {
if (!mp[i][j]) {
if (lst) q.push_back(make(lst, j-1)), lst=0;
}
else {
if (!lst) lst=j;
}
}
// cout<<"ttop: "<<ttop<<endl;
// cout<<"pre_tem: "; for (int j=1; j<=ttop; ++j) cout<<tem[j].fir<<','<<tem[j].sec<<' '; cout<<endl;
while (q.size()) {
u=q.front(); q.pop_front();
// cout<<"u: "<<u.fir<<' '<<u.sec<<endl;
for (int j=1; j<=top; ++j) {
if (sta[j].fir==u.fir) {
// cout<<"pos1"<<endl;
if (u.sec<sta[j].sec) {
tem[++ttop]=u; ++ans;
sta[++top]=make(u.sec+1, sta[j].sec);
sort(sta+1, sta+top+1);
}
else if (u.sec==sta[j].sec) tem[++ttop]=u;
else tem[++ttop]=make(u.fir, sta[j].sec), q.push_front(make(sta[j].sec+1, u.sec));
goto jump;
}
else if (sta[j].sec==u.sec) {
// cout<<"pos2"<<endl;
if (u.fir>sta[j].fir) {
tem[++ttop]=u; ++ans;
sta[++top]=make(sta[j].fir, u.fir-1);
sort(sta+1, sta+top+1);
}
else if (u.fir==sta[j].fir) tem[ttop]=u;
else tem[++ttop]=make(sta[j].fir, u.sec), q.push_front(make(u.fir, sta[j].fir-1));
goto jump;
}
}
tem[++ttop]=u, ++ans;
jump: ;
}
// cout<<"ttop: "<<ttop<<endl;
// cout<<"tem: "; for (int j=1; j<=ttop; ++j) cout<<tem[j].fir<<','<<tem[j].sec<<' '; cout<<endl;
top=ttop; ttop=0;
for (int j=1; j<=top; ++j) sta[j]=tem[j];
}
printf("%d\n", ans);
exit(0);
}
}
namespace task2{
int top, ttop, ans;
struct range{
int fir, sec;
set<pair<int, int>> s;
range():fir(0),sec(0){}
range(int a, int b):fir(a),sec(b){}
pair<range, range> split(int mid) {
range a(fir, mid), b(mid+1, sec);
for (auto it:s) {
if ( (it.fir==fir&&it.sec==mid) || (it.fir==mid+1&&it.sec==sec) ) --ans;
else if (it.sec<=mid) a.s.insert(it);
else if (it.fir>mid) b.s.insert(it);
}
return make(a, b);
}
};
inline bool operator < (range a, range b) {return a.fir==b.fir?a.sec<b.sec:a.fir<b.fir;}
inline bool operator == (range a, range b) {return a.fir==b.fir&&a.sec==b.sec;}
range sta[N], tem[N];
deque<range> q;
int solve() {
top=ttop=ans=0;
memset(sta, 0, sizeof(sta));
memset(tem, 0, sizeof(tem));
// for (int i=1; i<N; ++i) sta[i]=range(0, 0), tem[i]=range(0, 0);
while (q.size()) q.pop_front();
range u;
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
// cout<<"top: "<<top<<endl;
// cout<<"sta: "; for (int j=1; j<=top; ++j) cout<<sta[j].fir<<','<<sta[j].sec<<' '; cout<<endl;
int lst=0;
for (int j=1; j<=m+1; ++j) {
if (!mp[i][j]) {
if (lst) q.push_back(range(lst, j-1)), lst=0;
}
else {
if (!lst) lst=j;
}
}
// cout<<"ttop: "<<ttop<<endl;
// cout<<"pre_tem: "; for (int j=1; j<=ttop; ++j) cout<<tem[j].fir<<','<<tem[j].sec<<' '; cout<<endl;
while (q.size()) {
u=q.front(); q.pop_front();
// cout<<"u: "<<u.fir<<' '<<u.sec<<endl;
for (int j=1; j<=top; ++j) {
if (sta[j].fir==u.fir) {
// cout<<"pos1"<<endl;
if (u.sec<sta[j].sec) {
int dlt=1;
// for (auto it:sta[j].s) if (it.fir==u.fir&&it.sec==u.sec) {dlt=0; break;}
ans+=dlt;
tem[++ttop]=u;
// sta[++top]=range(u.sec+1, sta[j].sec);
pair<range, range> tem=sta[j].split(u.sec);
sta[j]=tem.fir; sta[++top]=tem.sec;
sort(sta+1, sta+top+1);
}
else if (u.sec==sta[j].sec) tem[++ttop]=u;
else tem[++ttop]=range(u.fir, sta[j].sec), q.push_front(range(sta[j].sec+1, u.sec));
goto jump;
}
else if (sta[j].sec==u.sec) {
// cout<<"pos2"<<endl;
if (u.fir>sta[j].fir) {
int dlt=1;
// for (auto it:sta[j].s) if (it.fir==u.fir&&it.sec==u.sec) {dlt=0; break;}
ans+=dlt;
tem[++ttop]=u;
// sta[++top]=range(sta[j].fir, u.fir-1);
pair<range, range> tem=sta[j].split(u.fir-1);
sta[j]=tem.fir; sta[++top]=tem.sec;
sort(sta+1, sta+top+1);
}
else if (u.fir==sta[j].fir) tem[ttop]=u;
else tem[++ttop]=range(sta[j].fir, u.sec), q.push_front(range(u.fir, sta[j].fir-1));
goto jump;
}
}
tem[++ttop]=u, ++ans;
jump: ;
}
// cout<<"ttop: "<<ttop<<endl;
// cout<<"tem: "; for (int j=1; j<=ttop; ++j) cout<<tem[j].fir<<','<<tem[j].sec<<' '; cout<<endl;
for (int j=1; j<=ttop; ++j) {
for (int k=1; k<=top; ++k) {
if (tem[j].fir<=sta[k].fir && tem[j].sec>=sta[k].sec) {
if (tem[j].fir==sta[k].fir && tem[j].sec==sta[k].sec) {
for (auto it:sta[k].s) tem[j].s.insert(it);
}
else {
tem[j].s.insert(make(sta[k].fir, sta[k].sec));
}
}
}
}
top=ttop; ttop=0;
for (int j=1; j<=top; ++j) sta[j]=tem[j];
}
return ans;
}
}
namespace task{
int dp[110][1<<8];
void solve() {
int lim=1<<m;
memset(dp, 0x3f, sizeof(dp));
dp[0][0]=0;
for (int i=1; i<=n; ++i) {
for (int s=0,s2,cnts; s<lim; ++s) {
for (int j=0; j<m; ++j) {
if (!mp[i-1][j+1]&&(s&(1<<j))) goto jump1;
if (!(s&(1<<j)) && mp[i-1][j+1] && !mp[i-1][j+2]) goto jump1;
}
s2=s; cnts=0;
if (s2) do {++cnts; s2&=s2-1;} while (s2);
for (int t=0,s2,cntt; t<lim; ++t) {
for (int j=0; j<m; ++j) {
// if (!t) cout<<"check: "<<bool(t&(1<<j))<<' '<<mp[i][j+1]<<' '<<mp[i][j+2]<<endl;
if (!mp[i][j+1]&&(t&(1<<j))) goto jump2;
if (!(t&(1<<j)) && mp[i][j+1] && !mp[i][j+2]) goto jump2;
}
s2=t; cntt=0;
if (s2) do {++cntt; s2&=s2-1;} while (s2);
// cout<<"i: "<<i<<' '<<bitset<5>(s)<<' '<<bitset<5>(t)<<' '<<dp[i-1][s]<<' '<<cntt<<endl;
for (int k=m-1,lst=0; ~k; --k) {
// cout<<"k&lst: "<<k<<' '<<lst<<endl;
if ((s&(1<<k))&&(t&(1<<k))&&mp[i-1][k+1]&&mp[i][k+1]) {
// cout<<"k1: "<<k<<endl;
if (lst) --cntt; //, cout<<"-1"<<endl;
lst=k+1;
}
else {
// cout<<"k2: "<<k<<endl;
if ( (!mp[i-1][k+1]&&!mp[i][k+1]&&!(s&(1<<k))&&!(t&(1<<k))) || (mp[i-1][k+1]&&!mp[i][k+1]&&(s&(1<<k))) || (!mp[i-1][k+1]&&mp[i][k+1]&&(t&(1<<k))) ) {
if (lst) --cntt; //, cout<<"<-1>"<<endl;
}
if (mp[i-1][k+1]&&mp[i][k+1]&&!(s&(1<<k))&&!(t&(1<<k))) ;
else lst=0;
}
if (!k && lst) --cntt; //, cout<<"(-1)"<<endl;
}
// cout<<"cntt: "<<cntt<<endl;
dp[i][t]=min(dp[i][t], dp[i-1][s]+cntt);
jump2: ;
}
jump1: ;
}
}
int ans=INF;
for (int s=0; s<lim; ++s) ans=min(ans, dp[n][s]);
printf("%d\n", ans);
exit(0);
}
}
signed main()
{
freopen("merging.in", "r", stdin);
freopen("merging.out", "w", stdout);
n=read(); m=read();
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) mp[i][j]=read();
task::solve();
return 0;
}