t1假硬币poj1013
思路:
首先要知道题目已经是知道称量结果的,并且每次输入都是三组数据,故定义三个字符数组,分别用来存放左边天平的三组数据、右边天平的三组数据和称量结果的三组数据,再定义一个用来判断是否是假币的数组,要注意这里不知道假币的轻重故需要自己判断,然后运用枚举的方法,把每一枚硬币进行判断是否是假币
代码如下:
#include<iostream>
#include <cstring>
using namespace std;
char Left[3][7];
char Right[3][7];
char result[3][7];
bool IsFake(char c, bool light);
int main() {
int t;
cin >> t;
while (t--) {
for (int i = 0; i < 3; ++i) cin >> Left[i] >> Right[i] >> result[i];
for (char c = 'A'; c <= 'L'; c++) {
if (IsFake(c, true)) {
cout << c << " is the counterfeit coin and it is light.\n";
break;
}
else if (IsFake(c, false)) {
cout << c << " is the counterfeit coin and it is heavy.\n";
break;
}
}
}
return 0;
}
bool IsFake(char c, bool light)
{
for (int i = 0; i < 3; ++i) {
char* pLeft, * pRight;
if (light) {
pLeft = Left[i];
pRight = Right[i];
}
else {
pLeft = Right[i];
pRight = Left[i];
}
switch (result[i][0]) {
case 'u':
if (strchr(pRight, c) == NULL)
return false;
break;
case 'e':
if (strchr(pLeft, c) || strchr(pRight, c))
return false;
break;
case 'd':
if (strchr(pLeft, c) == NULL)
return false;
break;
}
}
return true;
}
难点:
个人觉得最难的在于判断硬币是否位假币且是轻是重的这个函数,首先这个函数为bool型,传入的参数为一个字符(硬币)和一个bool型的light(轻重),第一步定义两个指针,先假设这枚硬币是轻的就把左边的硬币放入pLeft,右边的放入pRight,然后用switch case函数对结果数据(result)的首字母来判断天平的状态(要注意这里的up,even,down都是以右边天平为参考的,也就是up的意思是右边天平升起)故假如硬币是重的则要将刚开始的指针左右对换。
t2熄灯问题poj1222
思路:
首先得知道要使全部灯都恰好熄灭,由第一行的灯来决定,也就是我们只需要通过枚举的方法来遍历第一行灯熄灭的所有排列方式也就是2的6次方-1个(0~63),直到最后一行也全部熄灭来作为结束条件。
代码如下:
#include <bitset>
#include <memory>
#include <cstring>
#include <iostream>
using namespace std;
bitset<6> source[5], result[5], lights[5];
bitset<6> line; //000000~111111 0-2^6-1
void input_source()
{
int x;
for (int i = 0; i < 5; i++)
for (int j = 0; j < 6; j++)
{
cin >> x;
source[i][j] = x;
}
}
void output_result()
{
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 6; j++)
cout << result[i][j] << " ";
cout << endl;
}
}
int main()
{
int t = 0;
cin >> t;
for (int i = 0; i < t; i++)
{
input_source();
for (int n = 0; n < 64; n++)
{
memcpy(lights, source, sizeof(source));
line = n;
for (int k = 0; k < 5; k++)
{
result[k] = line;
for (int j = 0; j < 6; j++)
{
if (line.test(j))
{
lights[k][j].flip();
lights[k + 1][j].flip();
if (j > 0) lights[k][j - 1].flip();
if (j < 5) lights[k][j + 1].flip();
}
}
line = lights[k];
}
if (lights[4].none())
{
cout << "PUZZLE #" << i + 1 << endl;
output_result();
break;
}
}
}
}
难点:
用二进制0,1形成的矩阵来代替灯的熄灭的情况,这里调用了bitset库定义了一个5行6bit的组合,之后就根据题意分析写
t3特殊密码锁openjudge 8469
思路:
和熄灯问题(poj p1222)很像,只要枚举第一个按钮是否按下的两种情况即可。并且,第一种情况确定了后面情况也确定了。
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
//枚举第一个按钮是否按下的两种情况即可。对于指定的一种情况,后面的情况也随之确定了
int orilock;
int lock;
int destlock;
void setbit(int& n, int i, int v)//将n的第i位置为v
{
if (v)
n |= (1 << i);
else
n &= ~(1 << i);
}
void flipbit(int& n, int i)//对n的第i位取反
{
n ^= (1 << i);
}
int getbit(int n, int i)//取n的第i位
{
return (n >> i) & 1;
}
int main()
{
char line[40];
destlock = lock = orilock = 0;
cin >> line;
int n = strlen(line);
for (int i = 0; i < n; ++i)
setbit(orilock, i, line[i] - '0');
cin >> line;
for (int i = 0; i < n; ++i)
setbit(destlock, i, line[i] - '0');
int mintimes = 1 << 30 ;
for (int p = 0; p < 2; ++p)//第一个按钮有两种可能,按或者不按
{
lock = orilock;
int times = 0;
int curbutton = p;
for (int i = 0; i < n; ++i)
{
if (curbutton)
{
++times;
if (i > 0)
flipbit(lock, i - 1);
flipbit(lock, i);
if (i < n - 1)
flipbit(lock, i + 1);
}
if (getbit(lock, i) != getbit(destlock, i))
curbutton = 1;
else
curbutton = 0;
}
if (lock == destlock)
mintimes = min(mintimes, times);
}
if (mintimes == 1 << 30)
cout << "impossible" << endl;
else
cout << mintimes << endl;
return 0;
}
总结:
本人也是初次学习算法,也又很多不懂,写这个也是为了对自己学习的总结,如果看不懂代码的意思的话可以自己在草稿纸上代入数据进行计算,我是在mooc上视频学的(也看了很多遍才懂),总之算法学习是个长期且艰难的过程,第一遍没看懂就看第二遍直到看懂为止,加油吧!