真的吐了,写了五六个小时。
首先我们不考虑两边都能走,只考虑向左走,那么的话如果两个从左到右的集合分别为\(S1,S2\),则\(S1\subset S2\),且除去\(S1\)已经匹配掉的部分,剩下的点在\(S2\)中必定单调。这两个就是充要条件。
仿照这个,设\(dp_{S,p1,p2,l1,l2}\)表示已经不用考虑的点在\(S\)里面,向左的考虑到\(p1\)的\(l1\)长度,向右的考虑到\(p2\)的\(l2\)长度。然后复杂度大概就是\(O(n^3a^22^n)\)。
但是实现起来细节一大堆。这里大概罗列几点。
向左走的要一开始就放进去,否则无法对接下来要放的向右走做出限制,向右走的则不能一开始就放进去。
到最后向左走的可以停止,这样会少掉对向右走的限制,可以再记录一下。
有些时候不一定能匹配就匹配更优,可以不匹配以减少限制。
还有自己犯的一个sb错误,循环顺序错乱。
反正就这些。
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=10+5,M=(1<<10)+5,K=2e3+5,mod=1e9+7,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;mt19937 rnd(time(0));
int n,m,k,x,y,z,A[N][N],T[N],g[N][N],dp[M][N][N][N][N],Ans=1e9,p[N][N],p1[N][N],p2[N][N],Ts[N];
void chkmin(int &x,int y){x>y&&(x=y);}
int main(){
freopen("1.in","r",stdin);
int i,j,h,x,y,k;scanf("%d",&n);for(i=1;i<=n;T[i]--,i++) while(scanf("%d",&A[i][++T[i]]),A[i][T[i]])Ts[i]|=(1<<A[i][T[i]]-1);
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){x=T[j];for(h=T[i];h;h--){while(x&&A[j][x]^A[i][h]) x--;if(!x) {g[i][j]=h;break;}}p[i][j]=((Ts[i]&Ts[j])==Ts[i]);}
}Me(dp,0x3f);for(i=1;i<=n;i++) dp[1<<i-1][i][0][T[i]][0]=0;
for(i=0;i<(1<<n);i++)for(j=n;~j;j--)for(h=0;h<=n;h++)for(x=T[j];~x;x--)for(y=0;y<=T[h];y++){if(dp[i][j][h][x][y]>1e9) continue;
if(x) {
z=A[j][x];int Fl=0;for(k=1;k<=y+1;k++) if(A[h][k]==z){Fl=1;break;}
if(Fl||!h){
if(A[h][y+1]==z)chkin(dp[i][j][h][x-1][y+1],dp[i][j][h][x][y]+1);
else chkmin(dp[i][j][h][x-1][y],dp[i][j][h][x][y]+1);
}
}
if(y^T[h]){
z=A[h][y+1];int Fl=0;for(k=1;k<=x;k++) if(A[j][k]==z) {Fl=1;break;}
if(Fl||!j){
if(A[j][x]==z) chkmin(dp[i][j][h][x-1][y+1],dp[i][j][h][x][y]+1);
else
chkmin(dp[i][j][h][x][y+1],dp[i][j][h][x][y]+1);
}
}
if(!x&&j){
for(k=1;k<=n;k++){if(i>>(k-1)&1||!p[j][k]) continue;
for(int P=T[k];P>=g[k][j];P--) chkmin(dp[i|(1<<k-1)][k][h][P][y],dp[i][j][h][x][y]);
}
chkmin(dp[i][0][h][0][y],dp[i][j][h][x][y]);
}
if(!h) for(k=1;k<=n;k++) !(i>>(k-1)&1)&&(chkmin(dp[i|(1<<k-1)][j][k][x][0],dp[i][j][h][x][y]),0);
else for(k=1;k<=n;k++) !(i>>(k-1)&1)&&g[h][k]<=y&&p[k][h]&&(chkmin(dp[i|(1<<k-1)][j][k][x][0],dp[i][j][h][x][y]),0);
}
for(i=0;i<=n;i++) for(j=0;j<=n;j++) chkmin(Ans,dp[(1<<n)-1][i][j][0][T[j]]);
printf("%d\n",Ans>=1e9?-1:Ans);
}
标签:Integers,&&,int,luogu,向右走,CERC2016,using,dp,define
From: https://www.cnblogs.com/275307894a/p/16800300.html