URAL 1495. One-two, One-two 2
来源:互联网 发布:windows禁止ping 编辑:程序博客网 时间:2024/05/16 11:26
dp[ i ][ j ] 表示 长度为 i 的 对 n 取余为 j (若 j == 0 , j = n) 的最优解。
mod[1][ i ] 表示1 * (10)^(i-1) 对 n 取余的余数,若 (mod[1][ i ] == 0 ,则 mod[ 1 ][ i ] = n)。mod[2][ i ]同理。
状态转移方程 dp[ i ][ j ] = min(dp[ i-1 ][j - mod[1][ i- 1]] + 1*(10)^(i-1) , dp[ i-1 ][j - mod[2][ i- 1]] + 2*(10)^(i-1) )。
状态转移方程很像背包,但是若按背包那样去求解,最坏的时间复杂度会到 30*100W。应该会TLE,我没有去试。。
但是如果从 长度为 i 的状态 推出 长度为 i+1 的状态,即用BFS的方式从前往后推,时间复杂度很降低很多,但是依然TLE了。
原因在于无法确定推出的状态是否为最优解,因为 dp[i+1][ j ] 会从dp[ i ][ k ]推出多种方案。使得许多无用的状态都被计算了一次。
好吧,现在已经找到了剪枝的关键点,即剪掉这些无用的状态。
acc[ i ][ j ] 记录已经出现的解中最优的一个。从而使得加入BFS队列中的方案越来越靠近最优解,即最后一个加入队列的关于 dp[ i ][ j ]的解即为此种状态下的最优解。
还有一个问题就是最终的答案的值可能是个大数,但是因为只有1 和 2 ,所以可以用二进制来解决。
另外,int 的 30*100W的数组貌似会超内存,所以注意用滚动数组优化。
#include <iostream>#include <algorithm>#include <cstdlib>#include <cstdio>#include <cstring>#include <queue>#include <cmath>#include <stack>#pragma comment(linker, "/STACK:1024000000");#define EPS (1e-6)#define LL long long int#define ULL unsigned long long int#define _LL __int64#define _INF 0x3f3f3f3f#define INF 40000000#define Mod 1000000007using namespace std;int mod[3][33];struct N{ int ans,num;} acc[2][1000010];int ans[2][1000010];struct Q{ int ans,num,acc;};void Output(int n,int ans){ int temp = acc[ans%2][n].num; int num[31],top = 0; while(ans >= 1) { num[top++] = temp%2; temp /= 2; ans--; } for(top--; top >= 0; top--) { printf("%d",num[top]+1); } puts("");}void bfs(int n){ memset(acc,0,sizeof(acc)); memset(ans,0,sizeof(ans)); queue<Q> q; Q f,t; f.acc = mod[2][1]; f.ans = 1; f.num = 1; q.push(f); ans[1][mod[2][1]]++; acc[1][mod[2][1]].ans = 1; acc[1][mod[2][1]].num = 1; f.acc = mod[1][1]; f.ans = 1; f.num = 0; q.push(f); ans[1][mod[1][1]]++; acc[1][mod[1][1]].ans = 1; acc[1][mod[1][1]].num = 0; while(q.empty() == false) { f = q.front(); q.pop(); if(ans[f.ans%2][f.acc] != 1) { ans[f.ans%2][f.acc]--; } else { ans[f.ans%2][f.acc] = 0; if(f.acc == n) { Output(n,f.ans); return ; } if(f.ans < 30 && acc[f.ans%2][f.acc].num == f.num ) { t.ans = f.ans+1; t.acc = (f.acc + mod[1][t.ans])%n; t.acc = (t.acc == 0 ? n : t.acc); t.num = f.num; if(acc[t.ans%2][t.acc].ans != t.ans || t.num < acc[t.ans%2][t.acc].num) { acc[t.ans%2][t.acc].ans = t.ans; acc[t.ans%2][t.acc].num = t.num; ans[t.ans%2][t.acc]++; q.push(t); } t.ans = f.ans+1; t.acc = (f.acc + mod[2][t.ans])%n; t.acc = (t.acc == 0 ? n : t.acc); t.num = f.num + (1<<(f.ans)); if(acc[t.ans%2][t.acc].ans != t.ans || t.num < acc[t.ans%2][t.acc].num) { acc[t.ans%2][t.acc].ans = t.ans; acc[t.ans%2][t.acc].num = t.num; ans[t.ans%2][t.acc]++; q.push(t); } } } } printf("Impossible\n");}int main(){ int n,i; scanf("%d",&n); if(n%10 == 5 || n%10 == 0) { printf("Impossible\n"); return 0; } mod[1][1] = 1%n; mod[1][1] = (mod[1][1] == 0 ? n : mod[1][1]); mod[2][1] = 2%n; mod[2][1] = (mod[2][1] == 0 ? n : mod[2][1]); for(i = 2; i <= 30; ++i) { mod[1][i] = (mod[1][i-1]*10)%n; mod[1][i] = (mod[1][i] == 0 ? n : mod[1][i]); mod[2][i] = (mod[2][i-1]*10)%n; mod[2][i] = (mod[2][i] == 0 ? n : mod[2][i]); } bfs(n); return 0;}
0 0
- URAL 1495. One-two, One-two 2
- URAL 1495. One-two, One-two 2
- URAL 1495. One-two, One-two 2 DP or BFS?
- URAL 1495. One-two, One-two 2(暴力枚举)
- 【构造】 URAL 1495 One-two, One-two 2
- URAL 1495 One-two, One-two 2 (BFS)
- 算法练习:URAL 1495 One-two, One-two 2
- Timus 1495. One-two, One-two 2
- URAL 1216 Two Pawns and One King
- One or Two
- test one two three
- Two minus one 游戏规则
- Two minus one Rules
- 12289 - One-Two-Three
- one+two问题
- one,two,three
- 算法练习2:Two fighters, one winner.
- 4-2-Two Stacks In One Array
- iOS中使用ZipArchive压缩和解压缩文件
- UDP接收数据报
- linux下ip地址认证多IP配置
- 如何解决安卓SDK无法下载Package的问题(转载)
- 转: JDBC常见面试题集锦(一)
- URAL 1495. One-two, One-two 2
- Linux下的socket编程
- C++至今不可替代
- linux 获取目录下的所有文件
- Oracle查询字符集类型
- 【STM32F030探索套件】序列之二 搭建编译环境
- 项目四~处理工人工资的问题(扩展2)
- Ubuntu 12.04 下git的安装与使用
- iOS – Xcode升级到5.1& iOS升级到iOS7.1问题