题目链接
https://www.luogu.org/problemnew/show/P2622
分析
这题有点不一样,每个开关可以重复使用那么用每个开关作为阶段似乎不太好,那么我们按照题意设$f[sta]$为达到$sta$这个状态最少操作次数,我们枚举到达下一个状态用了哪个开关,假设用了某个开关后的状态为$x$,显然$f[x]=min(f[x],f[sta]+1)$
于是我们倒着枚举状态作为阶段就好了
但是我忽然发现这好像并不能保证无后效性……
所以请不要相信以上内容,还是写状态压缩的最短路去吧 逃)
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cctype> #include <queue> #define ll long long #define ri register int using std::min; using std::max; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x;return ; } const int maxn=10005; const int inf=0x7fffffff; int n,m; int f[1<<10+1]; int op[103][10]; int main(){ int x,y,sz,sta; read(n),read(m); for(ri i=1;i<=m;i++){ for(ri j=1;j<=n;j++){ read(op[i][j]); } } sz=1<<n; memset(f,0x3f,sizeof(f)); f[sz-1]=0; for(ri k=sz-1;k>=0;k--){ for(ri i=1;i<=m;i++){ sta=k; for(ri j=0;j<n;j++){ if(op[i][j+1]==1&&(k&(1<<j)))sta=sta^(1<<j); else if(op[i][j+1]==-1&&(!(k&(1<<j))))sta=sta|(1<<j); } f[sta]=min(f[sta],f[k]+1); } } if(f[0]==f[sz])puts("-1"); else printf("%d\n",f[0]); return 0; }
|