这道题的解题思路?
题目是acm的题目,pku1084-square destroyer
大概题意:给你N*N个1*1的小正方形组成的大正方形,问你破坏哪些边可以使得这个大正方形不再拥有任何子正方形。初始的时候,它可能会自动缺少某些边。
#include<iostream>
#include<bitset>
using namespace std;
__int64 rest, cover[60], remain[60];
int size, cnt, ans, up[6][6];
bool stick[60]; //记录每根火柴是否被取走
//记录每一行每一根火柴的序号
//例如size = 3时
//up[0][i] = 1, 2, 3(1 <= i <= 3)
//up[1][i] = 8, 9, 10(1 <= i <= 3)
//up[2][i] = 15, 16, 17(1 <= i <= 3)
void initUp()
{
for(int i = 0; i < size; i ++) {
up[i][0] = i * (2 * size + 1);
for(int j = 1; j < size; j ++)
up[i][j] = up[i][j - 1] + 1;
}
}
//记录以序号firststic为正方形左上方的火柴作为第一根火柴,边长为sqsize的正方形的状态
void initCover(int firststick,int sqsize,__int64 mask)
{
int gap = 2 * size + 1;
int num = firststick;
for(int i = 0; i < sqsize; i ++) { //记录水平边的的火柴的状态
//cover[i]记录能由第i根火柴组成的正方形的状态
cover[num] |= mask; //第num根火柴是这个正方形的组成部分
cover[num + sqsize * gap] |= mask;
num ++;
}
num = firststick+size;
for(int i = 0; i < sqsize; i ++) { //记录竖边的火柴的状态
cover[num] |= mask;
cover[num + sqsize] |= mask;
num += gap;
}
}
void input()
{
int i, j, k, n;
cout<<"请输入正方形的边长:";
cin >> size; //整个正方形的边长
initUp();//记录每一行每一根火柴的序号
cout<<"请输入缺失火柴的数目:";
cin >> cnt; //缺失的火柴的根数
memset(stick, true, sizeof(stick));
if(cnt!=0) cout<<"请输入缺失火柴的编号:";
for(i = 0; i < cnt; i ++) {
cin >> n; //缺失的火柴的编号
stick[n - 1] = false; //被拿掉的火柴
}
__int64 mask = 1;
memset(cover, 0, sizeof(cover));
for(i = 1; i <= size; i ++) { //边长为i的正方形的状态
for(j = 0; j <= size - i; j ++) {
for(k = 0; k <= size - i; k ++) {
initCover(up[j][k], i, mask);
mask <<= 1; //mask = 1 << k表示第k个正方形
}
}
}
}
void modify()
{
int i, j, rec = 0;
for(i = 1; i <= size; i ++) rec += i * i;//正方形个数
rest = 1;
for(i = 1; i < rec; i ++) {//将rest的二进制每一位都设置为1
//由于size最多只到5,则rec 最多为63,故64位数足够表示
rest <<= 1;//左移1
rest += 1;//再加1
}
cnt = 2 * size * (size + 1); //记录火柴的根数
for(i = 0; i < cnt; i ++) {
if(! stick[i]) rest &= ~ cover[i]; //记录剩下的火柴组成的状态
}
for(i = 0; i < cnt; i ++) {
cover[i] &= rest; //由于有些火柴已被取掉,故必须更新cover[i]
}
for(i = 0; i < cnt; i ++) {
if(! stick[i]) continue;
for(j = 0; j < cnt; j ++) {
if(j != i && (cover[i] & cover[j]) == cover[j])//去掉重复集合
stick[j] = false;
}
}
int c = 0;
for(i = 0; i < cnt; i ++) {
//只记录有效的stick[i]的cover[i]状态
if(stick[i]) cover[c ++] = cover[i];
}
cnt = c;//重置火柴总数
remain[cnt - 1] = cover[cnt - 1];
for(i = cnt - 2; i >= 0; i --) {
//remain[i]表示第i根火柴和尚未被取走的火柴所能组成的正方形
remain[i] = remain[i + 1] | cover[i];
}
}
void dfs(int c,int last,__int64 state)
{
//假设当前取走火柴的方案已经能破坏掉剩下的所有正方形,则进行更新当前最优解
if(state == rest) ans = c;
else {
if(c < ans && (remain[last + 1] | state) == rest) {
for(int i = last + 1; i < cnt; i ++) {
//试着拿掉cover[i]所表示的火柴,这样所破坏掉的正方形就为state | cover[i]
if((cover[i] | state) > state)
dfs(c + 1, i, state | cover[i]);
//bitset<64> b(cover[i]);
//cout<<b<<endl;
}
}
}
}
int main()
{
input();
modify();
ans = 25;
dfs(0, -1, 0);
cout<<"至少拿走的火柴数目:";
cout << ans << endl;
system("pause");
return(0);
}
谁具体说一下解题思路么?
谢谢啦 。
大概题意:给你N*N个1*1的小正方形组成的大正方形,问你破坏哪些边可以使得这个大正方形不再拥有任何子正方形。初始的时候,它可能会自动缺少某些边。
#include<iostream>
#include<bitset>
using namespace std;
__int64 rest, cover[60], remain[60];
int size, cnt, ans, up[6][6];
bool stick[60]; //记录每根火柴是否被取走
//记录每一行每一根火柴的序号
//例如size = 3时
//up[0][i] = 1, 2, 3(1 <= i <= 3)
//up[1][i] = 8, 9, 10(1 <= i <= 3)
//up[2][i] = 15, 16, 17(1 <= i <= 3)
void initUp()
{
for(int i = 0; i < size; i ++) {
up[i][0] = i * (2 * size + 1);
for(int j = 1; j < size; j ++)
up[i][j] = up[i][j - 1] + 1;
}
}
//记录以序号firststic为正方形左上方的火柴作为第一根火柴,边长为sqsize的正方形的状态
void initCover(int firststick,int sqsize,__int64 mask)
{
int gap = 2 * size + 1;
int num = firststick;
for(int i = 0; i < sqsize; i ++) { //记录水平边的的火柴的状态
//cover[i]记录能由第i根火柴组成的正方形的状态
cover[num] |= mask; //第num根火柴是这个正方形的组成部分
cover[num + sqsize * gap] |= mask;
num ++;
}
num = firststick+size;
for(int i = 0; i < sqsize; i ++) { //记录竖边的火柴的状态
cover[num] |= mask;
cover[num + sqsize] |= mask;
num += gap;
}
}
void input()
{
int i, j, k, n;
cout<<"请输入正方形的边长:";
cin >> size; //整个正方形的边长
initUp();//记录每一行每一根火柴的序号
cout<<"请输入缺失火柴的数目:";
cin >> cnt; //缺失的火柴的根数
memset(stick, true, sizeof(stick));
if(cnt!=0) cout<<"请输入缺失火柴的编号:";
for(i = 0; i < cnt; i ++) {
cin >> n; //缺失的火柴的编号
stick[n - 1] = false; //被拿掉的火柴
}
__int64 mask = 1;
memset(cover, 0, sizeof(cover));
for(i = 1; i <= size; i ++) { //边长为i的正方形的状态
for(j = 0; j <= size - i; j ++) {
for(k = 0; k <= size - i; k ++) {
initCover(up[j][k], i, mask);
mask <<= 1; //mask = 1 << k表示第k个正方形
}
}
}
}
void modify()
{
int i, j, rec = 0;
for(i = 1; i <= size; i ++) rec += i * i;//正方形个数
rest = 1;
for(i = 1; i < rec; i ++) {//将rest的二进制每一位都设置为1
//由于size最多只到5,则rec 最多为63,故64位数足够表示
rest <<= 1;//左移1
rest += 1;//再加1
}
cnt = 2 * size * (size + 1); //记录火柴的根数
for(i = 0; i < cnt; i ++) {
if(! stick[i]) rest &= ~ cover[i]; //记录剩下的火柴组成的状态
}
for(i = 0; i < cnt; i ++) {
cover[i] &= rest; //由于有些火柴已被取掉,故必须更新cover[i]
}
for(i = 0; i < cnt; i ++) {
if(! stick[i]) continue;
for(j = 0; j < cnt; j ++) {
if(j != i && (cover[i] & cover[j]) == cover[j])//去掉重复集合
stick[j] = false;
}
}
int c = 0;
for(i = 0; i < cnt; i ++) {
//只记录有效的stick[i]的cover[i]状态
if(stick[i]) cover[c ++] = cover[i];
}
cnt = c;//重置火柴总数
remain[cnt - 1] = cover[cnt - 1];
for(i = cnt - 2; i >= 0; i --) {
//remain[i]表示第i根火柴和尚未被取走的火柴所能组成的正方形
remain[i] = remain[i + 1] | cover[i];
}
}
void dfs(int c,int last,__int64 state)
{
//假设当前取走火柴的方案已经能破坏掉剩下的所有正方形,则进行更新当前最优解
if(state == rest) ans = c;
else {
if(c < ans && (remain[last + 1] | state) == rest) {
for(int i = last + 1; i < cnt; i ++) {
//试着拿掉cover[i]所表示的火柴,这样所破坏掉的正方形就为state | cover[i]
if((cover[i] | state) > state)
dfs(c + 1, i, state | cover[i]);
//bitset<64> b(cover[i]);
//cout<<b<<endl;
}
}
}
}
int main()
{
input();
modify();
ans = 25;
dfs(0, -1, 0);
cout<<"至少拿走的火柴数目:";
cout << ans << endl;
system("pause");
return(0);
}
谁具体说一下解题思路么?
谢谢啦 。
...全文
相关推荐
2025春秋杯部分题目解题思路.docx
2025春秋杯部分题目解题思路CTF比赛题目合集,包含以下12道题 1. See anything in these pics? (第一天) 2. 压力大,写个脚本吧 (第一天) 3. 简单算术 (第一天) 4. easy_flask (第一天) 5. 你是小哈斯? (第一天) 6. 通往哈希的旅程 (第一天) 7. easy_code (第三天) 8. easy_phP (第三天) 9. riya (第三天) 10. 问卷 (第三天) 11. funny_rsa (第三天) 12. signtime (第三天) 这些题目涵盖了多个方向: 图片隐写 脚本编写 Web安全 密码学 哈希破解 PHP代码审计 RSA加密 数字签名
渗透测试初级面试题.doc
渗透解题思路以上十道入门题大家答得如何? 答对8道题及以上的同学,你已经掌握了部分渗透测试的基础知识; 答对5道题的的同学,你的基础还有待提高; 答对3道题及以下的小伙伴,我就不好意思说了…
非常有用的101道算法部分常见面试题(面试题目荟萃)
非常有用的101道算法部分常见面试题(面试题目荟萃),希望对大家找工作有帮助!!!!!!!!
75道程序员面试逻辑思维测试题.txt
75道程序员面试逻辑思维测试题,用于拓展程序员的逻辑思维能力~~~~~~~~~~~~~~~~~~~
小学奥数50道经典题与分析报告.doc
小学奥数50道经典题与分析报告.doc


