• 刷题记录(NC24623 Tree Decoration,NC16612 [NOIP2009]靶形数独,NC16665 [NOIP2004]虫食算)


    NC24623 Tree Decoration

    题目链接

    关键点:

    1、从根开始往下搜,搜到子节点,在满足子节点的情况下,看每一个父亲结点是否还需要装饰,如果需要就从他儿子里面找花费最少的,在那个特定的结点上装上装饰,所以每一次的遍历都要找孩子结点花费最小的

    1. # include
    2. using namespace std;
    3. typedef long long ll;
    4. const int N = 100000+10;
    5. ll fa[N], c[N], t[N], sz[N];
    6. int n, root;
    7. vectorint> >ve(N);
    8. ll find(int x)
    9. {
    10. // cout<<1<
    11. ll ans = 0;
    12. for (int i=0; isize(); i++)
    13. {
    14. int a = ve[x][i];
    15. ans += find(a);
    16. sz[x] += sz[a];
    17. t[x] = min(t[x], t[a]);
    18. }
    19. if (sz[x] < c[x])
    20. {
    21. ans += (c[x]-sz[x])*t[x];
    22. sz[x] = c[x];
    23. }
    24. return ans;
    25. }
    26. int main()
    27. {
    28. cin>>n;
    29. for (int i=1; i<=n; i++)
    30. {
    31. cin>>fa[i]>>c[i]>>t[i];
    32. // cout<<"1"<
    33. if (fa[i] == -1)
    34. root = i;
    35. else
    36. {
    37. ve[fa[i]].push_back(i);
    38. }
    39. }
    40. // cout<<1<
    41. cout<<find(1);
    42. return 0;
    43. }

    NC16612 [NOIP2009]靶形数独

    题目链接

    关键点:

    1、首先还是采用数独题目的做法,主要是如何优化

    2、我们可以采用对每一行的空格进行优化,先从空格最少的行开始搜索

    1. # include
    2. using namespace std;
    3. struct ty{
    4. int hang, kong;
    5. vector<int>lie;
    6. }h[10];
    7. int hang[10][10];
    8. int lie[10][10];
    9. int g[10][10];
    10. int t[10][10];
    11. int ans=-1;
    12. int cnt[10][10] = {
    13. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    14. 0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
    15. 0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
    16. 0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
    17. 0, 4, 4, 4, 5, 5, 5, 6, 6, 6,
    18. 0, 4, 4, 4, 5, 5, 5, 6, 6, 6,
    19. 0, 4, 4, 4, 5, 5, 5, 6, 6, 6,
    20. 0, 7, 7, 7, 8, 8, 8, 9, 9, 9,
    21. 0, 7, 7, 7, 8, 8, 8, 9, 9, 9,
    22. 0, 7, 7, 7, 8, 8, 8, 9, 9, 9,
    23. };
    24. int cheng[10][10] = {
    25. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    26. 0, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    27. 0, 6, 7, 7, 7, 7, 7, 7, 7, 6,
    28. 0, 6, 7, 8, 8, 8, 8, 8, 7, 6,
    29. 0, 6, 7, 8, 9, 9, 9, 8, 7, 6,
    30. 0, 6, 7, 8, 9, 10, 9, 8, 7, 6,
    31. 0, 6, 7, 8, 9, 9, 9, 8, 7, 6,
    32. 0, 6, 7, 8, 8, 8, 8, 8, 7, 6,
    33. 0, 6, 7, 7, 7, 7, 7, 7, 7, 6,
    34. 0, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    35. };
    36. bool cmp(ty t1, ty t2)
    37. {
    38. return t1.kong
    39. }
    40. void dfs(int ha, int l, int score)
    41. {
    42. if (ha == 10)
    43. {
    44. ans = max(ans, score);
    45. return;
    46. }
    47. int tmp = h[ha].hang;
    48. for (int i=1; i<=9; i++)
    49. {
    50. if (hang[tmp][i] || lie[h[ha].lie[l]][i] || g[cnt[tmp][h[ha].lie[l]]][i])
    51. continue;
    52. hang[tmp][i] = 1;
    53. lie[h[ha].lie[l]][i] = 1;
    54. g[cnt[tmp][h[ha].lie[l]]][i] = 1;
    55. if (l == h[ha].kong-1)
    56. dfs(ha+1, 0, score+i*cheng[tmp][h[ha].lie[l]]);
    57. else
    58. dfs(ha, l+1, score+i*cheng[tmp][h[ha].lie[l]]);
    59. hang[tmp][i] = 0;
    60. lie[h[ha].lie[l]][i] = 0;
    61. g[cnt[tmp][h[ha].lie[l]]][i] = 0;
    62. }
    63. }
    64. int main()
    65. {
    66. int res = 0;
    67. for (int i=1; i<=9; i++)
    68. {
    69. for (int j=1; j<=9; j++)
    70. {
    71. int x;
    72. cin>>x;
    73. t[i][j] = x;
    74. if (x!=0)
    75. {
    76. int c = cnt[i][j];
    77. hang[i][x] = 1;
    78. lie[j][x] = 1;
    79. g[c][x] = 1;
    80. res += x*cheng[i][j];
    81. }
    82. else
    83. {
    84. h[i].hang = i;
    85. h[i].kong++;
    86. h[i].lie.push_back(j);
    87. }
    88. }
    89. }
    90. sort(h+1, h+1+9, cmp);
    91. dfs(1, 0, res);
    92. cout<
    93. return 0;
    94. }

    NC16665 [NOIP2004]虫食算

    题目链接

    关键点:

    1、首先的想法是对于每一个字母从0-n-1一个个的去尝试,且字母转换可以改成数字的映射

    即0-A,1-B。。。。

    2、如何处理n进制,计算时的进位判断,%n即可

    3、如何剪枝:

    (1)可以从低位开始计算,即我们开三个数组,用来存三个字符串对应的数字,我们从第一位开始存,倒着遍历字符串

    1. for (int i=n-1; i>=0; i--)
    2. {
    3. a[i] = s1[i]-'A';
    4. b[i] = s2[i]-'A';
    5. c[i] = s3[i]-'A';
    6. }

    (2)接下来是确定首先我们考虑的是哪个字母,同样的,我们也从最低位的字母开始选择,ne数组存的是每个字母的最佳的顺序(从最低位开始找顺序)

    1. for (int i=n-1; i>=0; i--)
    2. {
    3. if (vis[a[i]]==-1)
    4. {
    5. vis[a[i]] = 1;
    6. ne[++num] = a[i];
    7. }
    8. if (vis[b[i]]==-1)
    9. {
    10. vis[b[i]] = 1;
    11. ne[++num] = b[i];
    12. }
    13. if (vis[c[i]]==-1)
    14. {
    15. vis[c[i]] = 1;
    16. ne[++num] = c[i];
    17. }
    18. }

    (3)我们对于每一位,如果三个字符串的这一位都确定了,分别设三个字符串该位的数字为x1,

    x2,x3,如果x1+x2没有进位,那么(x1+x2)%n==x3,如果有进位,那么(x1+x2+1)%n==x3。

    1. for (int i=0; i
    2. {
    3. int x1 = ans[a[i]], x2 = ans[b[i]], x3 = ans[c[i]];
    4. if (x1 == -1 || x2 == -1 || x3 == -1)
    5. continue;
    6. if ((x1+x2)%n != x3 && (x1+x2+1)%n != x3)
    7. return false;
    8. }
    9. return true;

    4、如何判断最终答案正确,我们可以将每一个字符串算出其对应的数字,相加判断

    1. int check()
    2. {
    3. int ans1 = 0, ans2 = 0, ans3 = 0;
    4. for (int i=0; i
    5. {
    6. ans1 = n*ans1 + ans[a[i]];
    7. ans2 = n*ans2 + ans[b[i]];
    8. ans3 = n*ans3 + ans[c[i]];
    9. }
    10. if (ans1 + ans2 == ans3)
    11. return 1;
    12. else
    13. return 0;
    14. }

    完整代码:

    1. # include
    2. using namespace std;
    3. const int N = 30;
    4. int ans[N], a[N], b[N], c[N], ne[N], vis[N];
    5. int n, num, flag;
    6. string s1, s2, s3;
    7. int check()
    8. {
    9. int ans1 = 0, ans2 = 0, ans3 = 0;
    10. for (int i=0; i
    11. {
    12. ans1 = n*ans1 + ans[a[i]];
    13. ans2 = n*ans2 + ans[b[i]];
    14. ans3 = n*ans3 + ans[c[i]];
    15. }
    16. if (ans1 + ans2 == ans3)
    17. return 1;
    18. else
    19. return 0;
    20. }
    21. int find()
    22. {
    23. for (int i=0; i
    24. {
    25. int x1 = ans[a[i]], x2 = ans[b[i]], x3 = ans[c[i]];
    26. if (x1 == -1 || x2 == -1 || x3 == -1)
    27. continue;
    28. if ((x1+x2)%n != x3 && (x1+x2+1)%n != x3)
    29. return false;
    30. }
    31. return true;
    32. }
    33. void dfs(int x)
    34. {
    35. if (x == n+1)
    36. {
    37. if (check())
    38. {
    39. for (int i=0; i
    40. cout<" ";
    41. flag = 1;
    42. }
    43. return ;
    44. }
    45. if (flag)
    46. return ;
    47. if (!find())
    48. {
    49. return ;
    50. }
    51. for (int i=n-1; i>=0; i--)
    52. {
    53. if (vis[i] == -1)
    54. {
    55. vis[i] = 1;
    56. ans[ne[x]] = i;
    57. dfs(x+1);
    58. vis[i] = -1;
    59. ans[ne[x]] = -1;
    60. }
    61. }
    62. }
    63. int main()
    64. {
    65. cin>>n;
    66. cin>>s1>>s2>>s3;
    67. for (int i=n-1; i>=0; i--)
    68. {
    69. a[i] = s1[i]-'A';
    70. b[i] = s2[i]-'A';
    71. c[i] = s3[i]-'A';
    72. }
    73. memset(vis, -1, sizeof(vis));
    74. for (int i=n-1; i>=0; i--)
    75. {
    76. if (vis[a[i]]==-1)
    77. {
    78. vis[a[i]] = 1;
    79. ne[++num] = a[i];
    80. }
    81. if (vis[b[i]]==-1)
    82. {
    83. vis[b[i]] = 1;
    84. ne[++num] = b[i];
    85. }
    86. if (vis[c[i]]==-1)
    87. {
    88. vis[c[i]] = 1;
    89. ne[++num] = c[i];
    90. }
    91. }
    92. memset(vis, -1, sizeof(vis));
    93. memset(ans, -1, sizeof(ans));
    94. dfs(1);
    95. return 0;
    96. }

  • 相关阅读:
    如何从零开始解读产品经理行业分析
    Java知识记录
    Mybatis常用代码
    【太阳能多电平逆变器】采用SPWM技术的太阳能供电多电平逆变器研究(simulink)
    手把手教你搭建一个Minecraft 服务器
    DDOS防护如何建设?
    成都优优聚能带给你什么?
    Vue开发实例(五)修改项目入口&页面布局
    数据结构与算法之集合: Leetcode 349. 两个数组的交集 (Typescript版)
    基于C语言实现一个社交系统
  • 原文地址:https://blog.csdn.net/m0_60531106/article/details/126559094