题解 P4962 【朋也与光玉】

_虹_

2018-11-04 21:12:47

Solution

蒟蒻的首道状压题... 太蒟蒻,下面有些概念很可能会说的不准确。。。 这个程序可能算记忆化搜索的解法?(我还是觉得叫它剪枝搜索更直观。) 跑的出乎意料的快,吸氧总时间在720ms到790ms波动,最慢点170ms~180ms,不吸氧1100ms左右,考场上卡了我很久的#8这样剪枝之后用10ms就过了...(可能是数据比较适合这样写)~~(乱搞碾标算)~~ 比赛时的最优解,管理员神犇出现后的次优解(tql QAQ)。 时间复杂度:**O(玄学)** (理论上界应该很惨,但是基本上不可能达到,所以貌似没法算?)~~(能算也不会算,我太蒻了)~~ ```cpp #include <iostream> using namespace std; #define I_MAX 2147483647 const int kmaxn=100+5; int point[kmaxn];//该点颜色 int map[kmaxn][kmaxn];//邻接矩阵 int cut[32767+5][kmaxn];//cut[状态][当前位置]表示记录每个情况的最优解 int ans=I_MAX,n,m,k; int u,v,w; void dfs(int status,int pos,int dest,int deepth=1)//status的每个二进制位表示是否拿了这种光玉 { if((status>>point[pos])&1||ans<=dest||(cut[status][pos]!=0&&cut[status][pos]<=dest))//拿过的光玉重复或不可能是最优解,那就不走 return; if(deepth>=k)//都取完了,更新答案 { ans=min(ans,dest);//其实min没啥用,上面的if剪枝保证了dest<ans(刚发现) return; } cut[status][pos]=dest;//这应该属于记忆化吧,反正我是用来剪枝了,毕竟这个dfs函数没有返回值 status+=1<<point[pos];//更新当前状态 for(register int i=1;i<=n;++i)//遍历出边 { if(map[pos][i])dfs(status,i,dest+map[pos][i],deepth+1);//能走就试着走 } } int main() { ios::sync_with_stdio(false); cin>>n>>m>>k; for(register int i=1;i<=n;++i) { cin>>point[i]; } for(register int i=0;i<m;++i) { cin>>u>>v>>w; map[u][v]=w;//m最大为n(n-1),很适合邻接矩阵存边 } for(register int i=1;i<=n;++i) { dfs(0,i,0);//从每个点开始搜 } if(ans==I_MAX) { cout<<"Ushio!"<<endl; } else { cout<<ans<<endl; } return 0; } ``` 这篇题解只说记忆化(剪枝?),不写递推,因为我不会。。。。 最近爆了好几场0,明天还要期中考试,希望写个题解能rp++;~~也希望管理员给个通过。~~