腾讯笔试编程题交流

第一题

给出一个n个节点的无向图,所有节点之间都有通路,通路的权值都是0-9,起点在0号节点,目标是1号节点。有一个附加条件,你可以使k条边的权值减半,求最短路径。


解法来自大佬

dp[i][j][k]表示当前在i要走j步到1,还可以使用k次魔法,然后j从0到n-1 dp

第二题

你有很多硬币,面额为1,2,4,8,....,2^k,每种面额的硬币有两个,要求凑出n元来,输出不同的凑硬币方案的数目。


动态规划,下面代码是从评论的大佬重总结的。

// dp[i][j] 表示从最低的二进制位到第 i 位,j = 0 表示不能进位,j = 1 表示可以进位的方案数
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
ll n;
ll dp[100][2];

int main(void) {
    ll n;
    while (cin >> n) {
        memset(dp, 0, sizeof(dp));
        dp[0][0] = 1;
        dp[0][1] = 1;
        if (n & 1) dp[0][1] = 0;

        for (int i = 1; i <= 60; ++ i) {
            if (n & (1LL<<i)) {
                dp[i][0] += dp[i - 1][0];
                dp[i][0] += dp[i - 1][1];

                dp[i][1] += dp[i - 1][1];
            } else {
                dp[i][0] += dp[i - 1][0];

                dp[i][1] += dp[i - 1][0];
                dp[i][1] += dp[i - 1][1];
            }
        }
        cout << dp[60][0] << endl;
    }
    return 0;
}

第三题

输入4个数,a,b,A,B,可以对a,b进行两种操作,同时加一,或者乘2.
目标是使a==A,b==B,输出操作的最小次数。


下面代码是我和同学讨论之后得出的最优解了。

int method1(int a,int b,int A,int B){
    if(a>A || b>B) return -1;
    int c = a-b,
        d = A-B;
    if(c*d < 0) return -1;
    if(c==0 && d==0){
        // ok 
    }else if(c!=0 && d!=0){
        if(d%c!=0) return -1;
        int e = d/c;
        if(e&(e-1)!=0) return -1;
    }else return -1;
    int res = 0;
    while(true){
        if(A==a) return res;
        if(A%2==0){
            if(A/2>=a){
                A>>=1;
                res++;
            }else{
                res += A-a;
                return res;
            }
        }else{
            A-=1;
            res++;
        }
    }
}
#腾讯#
全部评论
第二题我的思路是类似于有序数组求合为定值的思路。小于的话较小数>>1,大于的话较大数<<1,等于的话counter+1...时间太紧张了不知道对不对
点赞 回复 分享
发布于 2017-09-13 16:57
// 第二个硬币问题,如果有错误,欢迎指正。 // dp[i][j] 表示从最低的二进制位到第 i 位,j = 0 表示无进位,j = 1 表示有进位的方案数 #include <bits/stdc++.h> using namespace std; using ll = long long; ll n; ll dp[100][2]; int main(void) { ll n; while (cin >> n) { memset(dp, 0, sizeof(dp)); dp[0][0] = 1; dp[0][1] = 1; if (n & 1) dp[0][1] = 0; for (int i = 1; i <= 60; ++ i) { if (n & (1LL<<i)) { dp[i][0] += dp[i - 1][0]; dp[i][0] += dp[i - 1][1]; dp[i][1] += dp[i - 1][1]; } else { dp[i][0] += dp[i - 1][0]; dp[i][1] += dp[i - 1][0]; dp[i][1] += dp[i - 1][1]; } } cout << dp[60][0] << endl; } return 0; } 第三题,我是直接贪心,从上往下不断的砍。。 #include <bits/stdc++.h> using namespace std; int main(void) { int a, b, A, B; while (cin >> a >> b >> A >> B) { bool flag = true; int ans = 0; while (A > a && B > b) { if (A % 2 == 0 && B % 2 == 0) { A /= 2; B /= 2; } else if (A % 2 == 1 && B % 2 == 1) { -- A; -- B; } else { flag = false; break; } ++ ans; } if (flag && A == a && B == b) cout << ans << endl; else cout << -1 << endl; } return 0; }
点赞 回复 分享
发布于 2017-09-13 17:00
第三题,我的思路是化成二进制比较不同的位数,试了几个过了但是不知道对不对-。-
点赞 回复 分享
发布于 2017-09-13 17:07
我只想笑😂
点赞 回复 分享
发布于 2017-09-13 16:56
不是说5点结束吗,4点40多就提示时间到了,刚好写完第一道题目后面两道都没看
点赞 回复 分享
发布于 2017-09-13 16:58
第一个跑的dfs 第三个,log(A - B) / (a - b)就是2的个数?,A - a * (A - B)/(a - b)为多项式部分然后再求1的个数?
点赞 回复 分享
发布于 2017-09-13 16:58
同第一题战略性放弃
点赞 回复 分享
发布于 2017-09-13 16:58
第三题也就只能DFS了吧(菜鸟轻喷)……  可能DFS到累加阶段能够直接加,不需要多次迭代了。。 我也就想到这一个优化的点。。 但是没时间了
点赞 回复 分享
发布于 2017-09-13 16:59
哎呀差不多
点赞 回复 分享
发布于 2017-09-13 17:00
战略性放弃。。。( ̄▽ ̄)"
点赞 回复 分享
发布于 2017-09-13 17:01
都是疯狂dfs,魔法王国那道暴力估计超时
点赞 回复 分享
发布于 2017-09-13 17:01
硬币那道题我是第一题。。。想着是拿动态规划做,大家帮我看看,为什么min_num就是不变呢==我觉得我逻辑没问题啊ORZ #include <iostream> using namespace std; void find_equal(int num1,int num2,int n,int total1,int total2,int &min_num){   if(num1==total1&&num2==total2){     if(n<min_num)       min_num=n;     return;   }   if(num1>total1)     return;   n=n+1;   find_equal(num1*2,num2*2,n,total1,total2,min_num);   find_equal(num1+1,num2*2,n,total1,total2,min_num); } int main() {     int a,b,A,B;   while(cin >> a >> b>>A>>B){     int min_num=100000;     find_equal(a,b,0,A,B,min_num);     if(min_num!=100000)       cout<<min_num<<endl;     else       cout<<"-1"<<endl;   } }
点赞 回复 分享
发布于 2017-09-13 17:01
第三题倒着推。 A是偶数则除以2,A是奇数则减一。  B同时操作。最后判断A==a B==b
点赞 回复 分享
发布于 2017-09-13 17:02
最短路那个我是dp[i][j][k]表示i到j用掉k次扫把的最短路径,然后跑floyd 最小次数那个就是普通的bfs应该没啥问题... 硬币是第一题手贱跳过去了...感觉是按二进制位的1和0找找规律统计一下...?
点赞 回复 分享
发布于 2017-09-13 17:02
看了大佬们的思路 我感觉自己真蠢 (sad
点赞 回复 分享
发布于 2017-09-13 17:04
第一题dp[i][j][k]表示当前在i要走j步到1,还可以使用k次魔法,然后j从0到n-1 dp 第二题猜的 n/2,如果n是2的k次方,答案再加1,理由是看成求n可以表示成多少种两个数的和 第三题没时间
点赞 回复 分享
发布于 2017-09-13 17:07
魔法王国DFS,机器那题我是直接贪心 从后面不断/2 然后再-1
点赞 回复 分享
发布于 2017-09-13 17:13
看到战略性放弃笑了
点赞 回复 分享
发布于 2017-09-13 17:17
//硬币问题 转化为二进制 //对于(7)111这类只有一种解法 //对于111.1000.0连续n个1,m个0的共有n * m +1种解法 //然后把二进制串分为x个连续的(11.100.0) //最左的一个(11.100.0) ans[0] = n0 * m0 +1; //先计算最右边两个 (11.100.0)(11.100.0),设有n1个1,m1个0;n0个1,m0个0,那么有 // ans[1] = (n1*m1+1)* (n0*m0+1) + m0中解法; //然后再和左边一个10串计算ans[2] = (n2*m2+1)* ans[1] + m1*ans[0]+ m0; //从优向左依次计算 #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { unsigned long long n; while(cin >> n) { vector<int> num; long long onezero[30][2]; long long ans[30]; while(n) { num.push_back( n & 1); n = n >> 1; } // for(int i = num.size()-1; i >=0; --i) // { // cout <<num[i]; // } // cout <<endl; int pair01 = 0; int cnt0 = 0; int cnt1 = 0; bool flag; while((flag = num.front())&& !num.empty()) { num.erase(num.begin()); } if(num.empty()) { cout << 1 <<endl; } else { for(int i = 0; i < num.size(); ++i) { if(num[i] == 1) { if(!flag) { onezero[pair01][0] = cnt0; cnt0 = 0; flag = true; } ++cnt1; if( i == num.size()-1) { onezero[pair01][1] = cnt1; } } else { if(flag) { onezero[pair01++][1] = cnt1; cnt1 = 0; flag = false; } ++cnt0; } } ans[0] = onezero[0][1] * onezero[0][0] +1; for(int k = 1; k <= pair01; ++k) { int join = onezero[0][0]; for(int j = 1; j < k; ++j) { join += onezero[j][0] * ans[j-1]; } ans[k] = (onezero[k][1] * onezero[k][0] +1) * ans[k-1] + join; } cout << ans[pair01]<<endl; } } return 0; }
点赞 回复 分享
发布于 2017-09-14 00:55

相关推荐

点赞 评论 收藏
分享
猪扒已出闸:方向不够聚焦,看不出来是想找什么方向的工作
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务