【贪心】P2660 zzc 种田
题目
P2660 zzc 种田
分析&&代码
这道题目不难,但是代码实现值得研究。
#include<iostream>using namespace std;int main()
{int x, y; cin >> x >> y;if(x > y) swap(x,y); //保持x最小 int ret = 0;while(y != 0){while(x <= y) {ret += x * 4;y -= x;} if(y) swap(x,y);}cout << ret;return 0;
}
这是我第一遍写出来的代码,我使用了while(x <= y)
这样一个循环来计算y能除多少次x,并且计算最后y剩下多少。但是再进一步想一下,除法和取模运算刚好可以直接代替这个循环,为什么要写一个循环我也不知道我是咋想的。这个循环非常耗时,x、y的数据范围是1e16,只能过三个点,其他的全部TLE。而且数据范围这么大要开LL。
于是代码改进成了这样:
#include<iostream>using namespace std;
typedef long long LL;
int main()
{LL x, y; cin >> x >> y;if(x > y) swap(x,y); //保持x最小 LL ret = 0;while(y != 0){LL cnt = y / x; ret += cnt * x * 4;y %= x; if(y) swap(x,y);}cout << ret;return 0;
}
再想想还有什么不足,似乎所有逻辑已经正确了,但是我们其实可以将代码写的更精炼。比如说比较x、y的大小然后交换这一步就可以优化。
下面是代码:
#include<iostream>using namespace std;
typedef long long LL;
LL ret;int main()
{LL x, y; cin >> x >> y;while(x && y){LL cnt = x / y;ret += cnt * y * 4;x %= y;swap(x, y);} cout << ret;return 0;
}
调试一下,假设 x=1,y=4,代码2一进程序就会比较 x、y 的大小,像现在这样 x 比 y 小就会交换 x、y 。但是对于优化后的代码,会直接进入循环,先计算出 cnt = 1/4 = 0,然后计算出 ret += 0 * 4 * 4,相当于ret不变,然后 1 %= 4 结果还是 1,最后一步交换 x、y。这就是优化后的代码可以不用手动交换 x、y。
递归写法:
#include <iostream>
using namespace std;
typedef long long LL;LL dfs(LL x, LL y, LL ret = 0)
{if (x == 0 || y == 0) return ret; // 终止条件LL cnt = x / y;ret += cnt * y * 4;x %= y;return dfs(y, x, ret); // 交换x,y并递归
}int main()
{LL x, y; cin >> x >> y;cout << dfs(x, y);return 0;
}
注意:函数中的ret是默认参数,默认参数允许函数在调用时省略某些参数,编译器会自动使用预先定义的默认值。