P1283 题解
一维状压 DP 做法
看到题解区要么用深搜,要么用二维 DP,于是来分享一下本题一维 DP 怎么做。
设
如果 DP 只有一维,那么转移就会相对困难一些,最直接的想法枚举每一个颜色哪些位置是能够涂的(根据贪心不难想到,位置数量越多越好),然后用现在的状态去更新未来的状态。
然而问题又出现了,如果一个矩阵的上方还有一个相同颜色的矩阵,且上方的矩阵在本轮中可以被涂,假设下方的矩阵在上方的矩阵更新后也可以被涂,那么实际上我们是更新不到下方的矩阵的。
为了解决这个问题,我们观察到
代码:
#include<bits/stdc++.h>
#define int long long
#define N 20
#define M 25
#define INF 1e18
using namespace std;
struct node{
int x,y,xx,yy,col;
}e[N];
int n,m,dp[1<<N],ned[M][M],c[M][M],qwq;
bool vis[N];
signed main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++){
cin>>e[i].y>>e[i].x>>e[i].yy>>e[i].xx>>e[i].col;
c[e[i].col][++c[e[i].col][0]]=i;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j&&e[j].yy==e[i].y&&e[j].xx>e[i].x&&e[j].x<e[i].xx){
ned[i][++ned[i][0]]=j;
}
}
}
for(int i=0;i<(1<<n);i++) dp[i]=INF;
dp[0]=0;
for(int i=0;i<(1<<n);i++){
for(int j=1,tot;j<=20;j++){
qwq=0,tot=100;
for(int i=1;i<=n;i++) vis[i]=false;
for(;tot--;)
for(int k=1;k<=c[j][0];k++){
int y=c[j][k],fl=1;
for(int q=1;q<=ned[y][0];q++){
if((1ll<<(ned[y][q]-1))&i||vis[ned[y][q]]) continue;
fl=0;break;
}
if(fl) vis[y]=true;
}
for(int i=1;i<=n;i++){
if(vis[i]) qwq+=(1ll<<(i-1));
}
dp[i|qwq]=min(dp[i|qwq],dp[i]+1);
}
}
cout<<dp[(1<<n)-1];
return 0;
}