UVA - 10271(chopsticks)

本文讨论了如何优化状态转移方程在代码实现中引入的额外维度,通过简化状态转移过程提高了效率。详细解释了原始代码逻辑,并提供了一个更简洁的版本,同时保持了相同的功能。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define INF 1200000000

const int maxn = 5003;
const int maxk = 1670;
int d[maxn][2][maxk],v[maxn],n;
bool vis[maxn][2][maxk];
int dp(int i,int j,int k){
if(vis[i][j][k]) return d[i][j][k];
vis[i][j][k] = true;

if(k==0) return d[i][j][k]=0;
int& ans=d[i][j][k];
ans=dp(i+2,1,k-1)+(v[i+1]-v[i+2])*(v[i+1]-v[i+2]);
if(n-i-1>=k*3) ans=min(ans,dp(i+1,0,k));
return ans;
}
int main()
{
    int T,k;
    scanf("%d",&T);
    while(T--){
          scanf("%d %d",&k,&n);
          k+=8;
          for(int i=1;i<=n;i++) scanf("%d",&v[i]);
          for(int i=0;i<=n;i++)
              for(int j=0;j<2;j++)
                 for(int kk=0;kk<=k;kk++) vis[i][j][kk]=false;
          printf("%d\n",dp(0,0,k));
    }
    return 0;
}



上面的版本是当时为了找到状态转移方程多加了一维,其实完全没必要


#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define INF 1200000000

const int maxn = 5003;
const int maxk = 1670;
int d[maxn][maxk],v[maxn],n;
bool vis[maxn][maxk];
int dp(int i,int k){
if(vis[i][k]) return d[i][k];
vis[i][k] = true;

if(k==0) return d[i][k]=0;
int& ans=d[i][k];
ans=dp(i+2,k-1)+(v[i+1]-v[i+2])*(v[i+1]-v[i+2]);
if(n-i-1>=k*3) ans=min(ans,dp(i+1,k));
return ans;
}
int main()
{
    int T,k;
    scanf("%d",&T);
    while(T--){
          scanf("%d %d",&k,&n);
          k+=8;
          for(int i=1;i<=n;i++) scanf("%d",&v[i]);
          for(int i=0;i<=n;i++)
                 for(int kk=0;kk<=k;kk++) vis[i][kk]=false;
          printf("%d\n",dp(0,k));
    }
    return 0;
}


在筷子搭配问题中,可使用动态规划思想计算 `dp[i][j]` 的值。`dp[i][j]` 表示在前 `i` 根筷子中选出 `j` 双筷子时的最小不和谐度之和。 以下是实现该问题的代码: ```cpp #include <cstdio> #include <algorithm> using namespace std; #define min(a, b) ((a) < (b) ? (a) : (b)) #define sqr(a) ((a) * (a)) int dp[110][55]; int n, k, a[110]; int main() { // 读取筷子数量 n 和需要的筷子对数 k scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); // 如果筷子数量不足,输出 -1 并结束程序 if (n < (k + 3) * 2) { puts("-1"); return 0; } // 对筷子长度进行排序 sort(a + 1, a + n + 1); // 初始化 dp 数组,将所有值设为一个较大的数 for (int i = 0; i <= n; i++) for (int j = 0; j <= k + 3; j++) dp[i][j] = 0x7ffffff; // 前 0 根筷子选 0 双筷子的不和谐度为 0 dp[0][0] = 0; // 动态规划过程 for (int i = 2; i <= n; i++) for (int j = 1; j <= k + 3; j++) { // 状态转移方程 dp[i][j] = min(dp[i - 1][j], dp[i - 2][j - 1] + sqr(a[i] - a[i - 1])); } // 输出结果,即前 n 根筷子中选出 k + 3 双筷子的最小不和谐度 printf("%d\n", dp[n][k + 3]); return 0; } ``` ### 代码解释: 1. **输入处理**:首先读取筷子的数量 `n` 和需要组成的筷子对数 `k`,并将每根筷子的长度存储在数组 `a` 中。如果 `n` 小于 `(k + 3)*2`,则无法组成所需的筷子对,程序输出 `-1` 并结束 [^4]。 2. **排序**:对存储筷子长度的数组 `a` 进行排序,这样相邻的筷子可以组成一对,从而便于后续计算不和谐度 [^4]。 3. **初始化**:将 `dp` 数组的所有元素初始化为一个较大的值 `0x7ffffff`,以表示初始状态下没有可行的方案。同时,将 `dp[0][0]` 初始化为 `0`,表示前 `0` 根筷子选 `0` 双筷子的不和谐度为 `0` [^4]。 4. **动态规划**:使用两层循环遍历所有可能的筷子数量 `i` 和筷子对数 `j`。对于每个状态 `dp[i][j]`,有两种选择:不选择第 `i` 根筷子 `dp[i - 1][j]`,或者选择第 `i` 根筷子与第 `i - 1` 根筷子组成一对 `dp[i - 2][j - 1] + sqr(a[i] - a[i - 1])`。取这两种选择中的最小值作为 `dp[i][j]` 的值 [^4]。 5. **输出结果**:最终结果存储在 `dp[n][k + 3]` 中,表示在前 `n` 根筷子中选出 `k + 3` 双筷子的最小不和谐度,将其输出 [^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值