最优化剪枝和可行性剪枝 |
poj1699 |
搜索的技巧和优化 |
poj3411, poj1724 |
记忆化搜索 |
poj3373,poj1691 |
最优化剪枝和可行性剪枝
POJ 1699
对这题无语了,爆搞TLE,加一个怎么也没想到的减枝47MS...
规模并不大,可以直接dfs,需要预处理一下,add[i][j]表示第j号串加在第i号串上增加的长度。。。这个计算的时候要注意。本菜就错在这上边wa了一上午!。
搜索的技巧和优化
poj 3411
题意:有m条路,N个顶点。从ai到bi的路要付费,付费有两种方式:1、比如之前去过ci,则可以在ci预付pi的费用。2、到达bi以后再付费,这样的费用是ri。求从1到N共的最小付费是多少。
题解:这题的规模不大,可以直接爆搞。但是,每条边的访问次数可以是多次。也就是说每个顶点可以访问多次,这样的话可以类似spfa的方法记录每一顶点的访问次数,当超过n次时conintue;当然还可以像POJ 1699一样加一个剪枝。cost记录dfs到当前的花费,如果cost >= ans则可以直接return;
poj 1724
题意:Bob要离家出走,从1号城市去N号城市。Bob手头有k money,每过一条路需要叫一点数目的money,否则不能通过,求在k money的承受范围内的最短路。
题解:话说3411时我想的一个错误的方法在这里居然可行,哈哈 ^_^。cat[u][v]表示u到v的边数。这样可以判出有环无环的情况,然后dfs。
void dfs(int u, int l, int k) { if(l >= ans) return ; if(u == n) { ans = Min(ans, l); return ; } int v, i; for(i = head[u]; i != -1; i = g[i].next) { v = g[i].to; if(!cat[u][v] || k - g[i].tl < 0) continue; cat[u][v] --; dfs(v, l + g[i].ln, k - g[i].tl); cat[u][v] ++; } }
记忆化搜索
彻底败给3373了,本菜估计要错出3373应该要两天时间。。。T_T
POJ 1691 (状压dp)
题意:有一个棋盘,划分成n个方格,每个方格涂相应的颜色,图色方案如下:
1、方格i能够被涂色当且仅当i正上方相邻的方格都被涂色;
2、比如现在要涂col1色,则所有要涂col1色且满足条件以的方格可以同时涂色;
求喷头至少要换几次能把方格涂完。
思路:表示真心没相当状态压缩可以这样写,我一直在纠结要怎么预处理棋盘。。。T_T!
共n个方格,每方格i一给它一个编号 1<<i。所有的方格都被涂色后的状态是 (1<<n) - 1(等比数列求和公式,可以自己算一下,其实从状态累加上就可以看出来。)
dp[x][i]表示当前状态为x,最后一次涂色的方格是i时的最优值。
dp[ns][i]转移时可以枚举上一次最后涂色的方格是j的值dp[s][i],然后转移,ns = s|(1<<i),表示i从状态j转移后被染色得到的新状态。详见代码:
int solve() { int s, i, j; int m = E(n), tmp, ns; REP(i, m) REP(j, n) dp[i][j] = inf; REP(i, n) if(!up[i]) dp[(1<<i)][i] = 1; //第一行,上边没有方块时的情况。 REP(s, m) { REP(i, n) { //当前状态为s时选一个没有被染色的方格i进行转移。 if(s&(1<<i)) continue; //被染色 if((s&up[i]) != up[i]) continue; //方格i整上方的方格没有全被染色 REP(j, n) { //枚举上一次最后染色为方格j时的情况,通过这个情况转移到i。 if((s&(1<<j)) == 0) continue; //j未被染色 ns = s|(1<<i); //转移到新状态 tmp = dp[s][j]; if(p[j].col != p[i].col) ++tmp; //颜色相同不用换喷头,颜色不同则要更换。 dp[ns][i] = Min(dp[ns][i], tmp); } } } int res = inf; REP(i, n) { res = Min(res, dp[m- 1][i]); } return res; }