当前位置: 首页 > backend >正文

NOIP 2009 模拟测试总结

NOIP 2009 模拟测试总结

前序

题目的难易安排挺合适的,第一题Spy和第二题Son都可以简单通过,从第三题开始就有点难度了。第三题Trade就有点难度,代码倒不难,只是模型转换和双向BFS方法难想到(其实第四题DFS也是万万想不到的),还有Tarjan加上拓扑排序的方法有些恶心……第四题靶形数独,貌似只能搜索,只不过有技巧

好了,开始正题。

Question1: 潜伏者 Spy

非常简单的一道题,可以用字母的ASCLL码或直接用map建立映射。
直接上代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;int tot = 0;
char ss1[105], ss2[105], ori[105];
bool word[27], exi[27];
map<char, char> trans;int main()
{freopen( "spy.in", "r", stdin );freopen( "spy.out", "w", stdout );memset( word, false, sizeof(word));memset( exi, false, sizeof(exi));scanf( "%s", ss1 );scanf( "%s", ss2 );scanf( "%s", ori );int len = strlen(ss1);for( int i = 0; i < len; i++ ){if( !exi[ss2[i]-'A'] ) tot++;exi[ss2[i]-'A'] = true;if( !word[ss1[i]-'A'] || trans[ss1[i]] == ss2[i] ){trans[ss1[i]] = ss2[i];word[ss1[i]-'A'] = true;}           else{printf( "Failed\n" );return 0;}}if( tot < 26 ) {printf( "Failed\n" );return 0;}int len1 = strlen(ori);for( int i = 0; i < len1; i++ ){if( !word[ori[i]-'A'] ){printf( "Failed\n" );return 0;}}for( int i = 0; i < len1; i++ ){printf( "%c", trans[ori[i]] );}return 0;
}

Question2: Hankson的趣味题 Son

小小的数论题,也是两种做法,一是枚举加判断,而是质因数分解。第一种好写很多,如果是直接写的话没法得满,要有点小技巧。

也不多说直接上代码:

组合判断套装

int gcd( int a, int b )
{b == 0 ? a : gcd( b, a%b );
}
int lcm( int a, int b )
{return a / gcd( a, b ) * b;
}
int cal( int x )
{if( gcd( x, a0 ) == a1 )if( lcm( x, b0 ) == b1 ) ans++;
}

循环枚举

while( n-- ){ans = 0;scanf( "%d%d%d%d", &a0, &a1, &b0, &b1 );for( int i = 1; i * i <= b1; i++ ){if( b1%i == 0 ){cal( i );if( i * i != b1 ) cal( b1 / i );}}printf( "%d\n", ans );}

有一点要注意,只用枚举到根号b1就行,否则要超时。


Question3: 最优贸易 Trade

本来一开始写的Tarjan,但是在缩点上出了点问题,最后折中输出了贪心最优值。考下来评讲才发现原来能用双向SPFA,非常巧妙!

具体思路就是,要得到最大利润,就要较低买入,较高卖出,所以就可以建立两个图,一个正向图(只保存正向边),一个反向图(只保存反向边),为什么呢?

其实是这样的。低价买入在高价卖出之前,所以我们要先找到一个从起点出发能够达到的最低价格(用low[i]数组保存从起点到i城能最低买入的价格),再用反向图从终点出发,寻找每一个能够到达的城市的最高卖出价(用high[i]表示从终点出发到i城能够卖出的最高价) ,到了这时,每个城市都有了两个属性——从起点到这个城市一路上最低买入价从终点到这个城市一路上最高卖出价,又终点和起点肯定是相通的,就只需枚举每一个城市计算高价减去低价的值,再在其中寻找最大值就行了。

代码:

inline void spfa_1()
{q.push(1);vis[1] = true;MIN[1] = Data[1];while(!q.empty()){int x = q.front();q.pop();vis[x] = false;for( int i = head[x][0];i;i = edge[i].next ){int v = edge[i].v;if( MIN[v] > MIN[x] || MIN[v] > Data[v] ){MIN[v] = min( MIN[x],Data[v] );if( !vis[v] ) q.push(v),vis[v] = true;}}}}inline void spfa_2()
{q.push(n);vis[n] = true;MAX[n] = Data[n];ans = max( ans,MAX[n] - MIN[n] );while( !q.empty() ){int x = q.front();q.pop();vis[x] = false;for( int i = head[x][1];i;i = edge[i].next ){int v = edge[i].v;if( MAX[v] < MAX[x] || MAX[v] < Data[v] ){MAX[v] = max( MAX[x],Data[v] );ans = max( MAX[v] - MIN[v],ans );if( !vis[v] ) q.push(v),vis[v] = true;}}} 
}

MAX[] 和MIN[] 分别保存上面提到的最高价和最低价。


Question4: 靶形数独 Sudoku

这题正解用深搜是我没想到的(不过也只有9 * 9 ,也是有道理的)
也算见识到了深搜的强大。
主要思想就是类似八皇后的回溯,搜索->放置->进入下一层->到达边界返回->复原再搜…..
思路非常简单,但是有技巧。首先只深搜是过不了的,很明显会TLE,所以要明智的选取对象。什么意思呢?
我们来回忆我们怎么做数独的。我们会选取剩余可能性最小的格子去填,这也就是核心思想,这可以使得搜索树变小,也就优化了时间,再加上二进制位运算来优化数字选取的过程,就可以过了。鉴于网上二进制的代码很多,我就放一个不用二进制的,初学者可以看一下。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;int map[10][10], val[10][10] = { {0, 0, 0, 0, 0, 0, 0, 0, 0},{0,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6},{0,6 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,6},                              {0,6, 7, 8, 8, 8, 8, 8, 7, 6},{0,6 ,7 ,8 ,9 ,9 ,9 ,8 ,7 ,6},{0,6 ,7 ,8 ,9 ,10, 9, 8, 7, 6},{0,6 ,7 ,8 ,9 ,9 ,9 ,8 ,7 ,6},{0,6, 7, 8, 8, 8, 8, 8, 7, 6},{0,6 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,6}, {0,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6},};
int box[10][10], ans = -1;
bool vis1[10][10], vis2[10][10], vis3[10][10];inline void dfs()
{int step = 10, x, y;for( register int i = 1; i <= 9; i++ )for( register int j = 1; j <= 9; j++ ){if( !map[i][j] ){int cnt = 0;for( int k = 1; k <= 9; k++ )if( !vis3[box[i][j]][k] && !vis1[i][k] && !vis2[j][k] )cnt++;if( cnt < step ){step = cnt;x = i, y = j;}}               }               if( step == 10 ){int tot = 0;for( int i = 1; i <= 9; i++ )for( int j = 1; j <= 9; j++ )tot += map[i][j] * val[i][j];ans = max( ans, tot );return; }for( int k = 1; k <= 9; k++ ){if( !vis3[box[x][y]][k] && !vis1[x][k] && !vis2[y][k] ){vis1[x][k] = vis2[y][k] = vis3[box[x][y]][k] = true;map[x][y] = k;dfs();map[x][y] = 0;vis1[x][k] = vis2[y][k] = vis3[box[x][y]][k] = false;}}   
}
int main()
{memset( vis1, false, sizeof(vis1));memset( vis2, false, sizeof(vis2));memset( vis3, false, sizeof(vis3));for( int i = 1; i <= 9; i++ )for( int j = 1; j <= 9; j++ ){cin>>map[i][j];box[i][j] = (i-1) / 3 * 3 + (j-1) / 3 + 1;if( map[i][j] ){       /**/if( vis1[i][map[i][j]] || vis2[j][map[i][j]] || vis3[box[i][j]][map[i][j]] ){printf( "-1\n" );return 0;}vis1[i][map[i][j]] = true;vis2[j][map[i][j]] = true;  vis3[box[i][j]][map[i][j]] = true;}}dfs();printf( "%d\n", ans );return 0;       
}

九宫格的判断还可以像我直接打表一样自己写在程序里。

http://www.xdnf.cn/news/11116.html

相关文章:

  • HTML做一个学校网站(纯html代码)
  • 【转】国外SCI、EI检索期刊
  • 非主流伤感QQ空间日志_享受着自己的那份孤独
  • 智能ABC输入法破解特别版5.23下载 - xp/windows7通用
  • Node详细解释[带你快速入门Node](1)
  • Android TableLayout
  • Qt Quick - 高仿微信局域网聊天 V5 版本
  • MATLAB中mean的用法
  • Android开发十大必备工具(图文)
  • SMO优化算法(Sequential minimal optimization)
  • C++string类的常用方法
  • 麻雀要革命2 第8节:莽撞的麻雀小姐
  • 找不到msvcp110.dll怎么办,msvcp110.dll丢失的5种修复方法
  • 完美越狱来了,unc0ver 更新 7.0.0 版本,但是别着急冲
  • 国内外主要的PHP开源CMS系统分析
  • TrueCrypt中文版怎么用?TrueCrypt使用方法及详细教程介绍
  • AI绘画draft:如何利用人工智能技术创造独特的艺术作品
  • 统一加速器发布 pro V0.9805 版本
  • 设计师必看的5款字体创意软件!
  • 图形学初识--视图+投影变换
  • WakeLock的介绍与使用
  • 【计算机考研408-计算机网络-教书匠视频笔记】主机访问浏览器的全部过程
  • HTML基础教程(非常详细)从零基础入门到精通,看完这一篇就够了。
  • Android开源项目第二篇——工具库篇
  • ModuleNotFoundError:如何解决 no module named Python 错误?
  • 驱动人生深度扫描功能上线!使用感怎么样?
  • 北大计算机学院 教授 湖南人,北大湘籍教授邹恒甫简历
  • 目标世界上最小的Linux系统—ttylinux体验
  • 分享116个图片JS特效,总有一款适合您
  • 免费php空间带域名,freehostia免费250MB无广告PHP空间可绑域名