This is tinymce plugins
因为项目需要用到富文本编辑器众多富文本编辑器中,选择了 Tinymce,根据项目需要对Tinymce 进行扩展和增强插件,记录一下,并同时分享给需要帮助的人。
QQ邮箱: fivecc@qq.com
This is tinymce plugins
该项目主要为 tinymce 富文本编译器的扩展插件,或增强优化插件
目前整理完成插件列表如下:
未使用过 tinymce ,可以查看莫若卿大佬的 tinymce 中文文档
增强效果:
tinymce.init({ selector: '#tinydemo', plugins: "image imagetools", toolbar: "image", });
点击下载 更多下载
更多配置 见 插件 / imagetools
增强效果:
提供一个配置项目 table_icons 自定义图标配置【Object】可配置icon 对象为
tinymce.init({ selector: '#tinydemo', plugins: "table", toolbar: "table" table_icons: {// 以下下为默认配置 'align-right-table': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm6 4h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm-6-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2z" fill-rule="evenodd"></path></svg>', 'align-left-table': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm0 4h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2z" fill-rule="evenodd"></path></svg>', 'align-center-table': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm3 4h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 1 1 0-2zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2zm-3-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2z" fill-rule="evenodd"></path></svg>' }});
点击下载 更多下载
更多配置 见 插件 / table
当使用 本项目 letterspacing 插件,如需使用首行缩进 请替换原有indent2em,使用该项目indent2em插件。
tinymce.init({ selector: '#tinydemo', plugins: "indent2em", toolbar: "indent2em"});
点击下载 更多下载
更多配置 见 插件 / indent2em
tinymce.init({ selector: '#tinydemo', plugins: "letterspacing", toolbar: "letterspacing"});
更多配置(选配) :
提供字段 letterspacing 配置参数【String类型】,空格隔开;
tinymce.init({ selector: '#tinydemo', plugins: "letterspacing", toolbar: "letterspacing", letterspacing: "0px 2px 4px 6px 24px"});
tinymce.init({ selector: '#tinydemo', plugins: "layout", toolbar: "layout"});
更多配置 (选配):
提供 一键布局 默认参数字段 layout_options 配置参数【Object类型】目前一共4个属性:
style : 一键布局默认样式参数【Object】
filterTags: 【Array】过滤标签,该数组中的标签,一键布局中将会被忽略(默认忽略 ‘table’,’tbody’,’td’,’tr’)
tagsStyle: 单独标签样式处理【Object】
clearStyle: 【Array】清除样式 ,一键布局后 ,数组中的样式将会清除掉。
配置优先级从低到高: style < filterTags < tagsStyle < clearStyle
tinymce.init({ selector: '#tinydemo', plugins: "layout", toolbar: "layout", layout_options: { style: { 'text-align':'justify', 'text-indent':'2em', 'line-height': 1.5 }, filterTags:['table>*','tbody'], //'table,'tbody','td','tr' 将会忽略掉 同时 table>*,忽略table 标签 以及所有子标签 clearStyle: ['text-indent'],//text-indent 将会被清除掉 tagsStyle: { 'table': { 'line-height': 3, 'text-align': 'center' }, 'table,tbody,tr,td': { //支持并集选择 'line-height': 2 }, 'tr>td,table>tbody': { //支持, 精准定位 通过 ' > ' 'line-height': 3, 'text-align': 'center' } } }});
tinymce.init({ selector: '#tinydemo', plugins: "importword", toolbar: "importword"});
更多配置(选配) :
提供 导入word 插件
预处理函数 importword_handler 配置参数【Function类型】传入3个参数
editor : editor 编辑器实列【object】
files : 导入的文件 【object】
next : 下一步骤回调函数 传入files标签字符串【Function】
过滤函数 importword_filter 配置参数【Function类型】传入3个参数
result : 导入word 生成的 html标签字符串【String】
insert : 插入回调函数 传入 html标签字符串【String】
message: 转换过程中产生的错误信息集【Array】
tinymce.init({ selector: '#tinydemo', plugins: "importword", toolbar: "importword", importword_handler: function(editor,files,next){ var file_name = files[0].name if(file_name.substr(file_name.lastIndexOf(".")+1)=='docx'){ notificationID = editor.notificationManager.open({ text: '正在转换中...', type: 'info', closeButton: false, }); next(files); }else{ editor.notificationManager.open({ text: '目前仅支持docx文件格式,若为doc111,请将扩展名改为docx', type: 'warning', }); } // next(files); } importword_filter: function(result,insert,message){ // 自定义操作部分 insert(result) //回插函数 }});
tinymce.init({ selector: '#tinydemo', plugins: "upfile", toolbar: "upfile"});
更多配置(选配) :
提供 upfile 插件 过滤函数 file_callback 配置参数【Function类型】传入2个参数
tinymce.init({ selector: '#tinydemo', plugins: "upfile", toolbar: "upfile", file_callback: function (file, succFun) { // 自定义处理文件操作部分 succFun(url,{text: 'xx.pdf'}) //成功回调函数 text 显示的文本 }});
测试次数
x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n为了减少测试次数,从每个厂家抽样3部手机参加测试。某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?请填写这个最多测试次数。注意:需要填写的是一个整数,不要填写任何多余内容。
此题 答案为19 通过关系式 (K^3+5K)/6>=1000 (下为详解)
解题思路:
先说说题意
一共 1000 层 某款手机的耐摔指数 为 1~1000的任何值(超出1000 也按1000算),每款手机只有三部一模一样的手机给我们测试用 也就是说 我们最多摔坏3次 而且 最后一次摔坏的层数就是该款手机的耐摔指数。你就需要制定一个最优的方案 适用与所有不同的手机测试并且测试次数要小于等于最坏情况下的次数。(最坏情况 就是 一个边界测试次数,无论手机的耐摔指数是多少,总能在这个边界测试次数前 找到该手机的耐摔指数)
此题 二分肯定莫法搞 只有 3部手机 ,如果 手机耐摔指数为10 你二分 先来500层 一扔 碎了 再来250层 又碎了 就剩一部手机了 咋办 你难道要扔 125 ,此时 你莫法 只有从老老实实从第一层 开始扔 才能扔到第10层测出结果,这样你就会扔 1+1+10 =12 次 ,需要测试12次 才能得到 该手机的耐摔指数,可是如果 该手机的耐摔指数为 249 哪 按照二分 就得 1+1+249=251次。所以必须另辟思路
如果 只有一部手机给你测试 哪只能 从第一层开始扔 最坏情况就是 从1扔到 1000层去,最坏情况就是1000次
如果 只有二部手机给你测试 ,这时候 就相当于多了一次机会 可以博上一博 减少点测试次数(准确的说是减少最坏情况下的测试次数),这个时候就需要假设一下了 ,最坏测试次数为 k 次 ,也就是说 无论你手机的耐摔指数为多少(1000内), 我都能通过k次测试 找到,那么想想
假设 第 1 次随便随便选一层扔 ,选 第 层 碎了,那么只好 从第1层 开始扔了
最坏就是 耐摔指数为 -1 要1+-1= 次测试 (同时保证 <=k) 若没碎就可以进行下一步
假设 第 2 次随便随便选一层扔 ,选第 层 碎了,那么只好 从第 +1层 开始扔了
最坏就是 耐摔指数为 -1 要1+1+( -1)- = -+1 次测试(同时保证 -+1 <=k)若没碎就可以进行下一步
假设 第 3次随便随便选一层扔 ,选第 层 碎了,那么只好 从第 +1层 开始扔了
最坏就是 耐摔指数为 -1 要1+1+(-1)- =- +2 次测试 (同时保证 - +2 <=k)若没碎就可以进行下一步
。
。
。
。
假设 第 k次随便随便选一层扔 ,选第 层 碎了,那么只好 从第+1层 开始扔了
最坏就是 耐摔指数为 -1 要1+1+1…1+(-1)-=-+(k-1) 次测试 (同时保证 -+(k-1) <=k, )
然后 我们把它们 给排一排 如下
<=k
-+1 <=k
- +2 <=k
……
-+(k-1) <=k
看到这样的 忍不住 就 想消消元 于是乎 如下
+ -+1+- +2…… -+(k-1)<=kk
消掉元之后: 1+2+3….+(k-1)+<=kk
前面常数求和公式 k(k-1)/2 +<=kk
再变一下 <=kk-k(k-1)/2 即得到 <=k(k+1)/2
再一想 是第k次 扔手机 所以 这是最后一次,要保证1~1000层所有情况都考虑即>=1000
要想测试次数k 最少 所以 当然取1000 于是乎 就得到
当给你两部手时 在最坏情况下最小测试次数满足 k(k+1)/2>=1000 那么k 就得出了
现在 给的是 三部 手机,则用同样的方法 设 最坏测试次数为 K 次 ,
假设 第 1 次随便随便选一层扔 ,选 第 层 碎了,碎了我也有2部手机不是,
那么 我此时想用两部手机测出 1~( -1)范围的耐摔指数就和上面情况一样的
最坏测试次数满足关系 k(k+1)/2>=-1= -1 (同时保证 k+1<=K,===>k<=K-1注 :这是大 K )
若没碎就可以进行下一步
假设 第 2 次随便随便选一层扔 ,选第 层 碎了,碎了我也有2部手机不是,
那么 我此时想用两部手机测出 ( +1)~( -1)范围的耐摔指数就和上面情况一样的
最坏测试次数满足关系 k(k+1)/2>=( -1)- =- -1 (同时保证 k+1+1 <=K,===>k<=K-2注 :这是大 K)
若没碎就可以进行下一步
假设 第 3 次随便随便选一层扔 ,选第 层 碎了,碎了我也有2部手机不是,
那么 我此时想用两部手机测出( +1)~( -1)范围的耐摔指数就和上面情况一样的
最坏测试次数满足关系 k(k+1)/2>=( -1)- =- -1 (同时保证 k+1+1+1 <=K,===>k<=K-3注 :这是大 K)
。
。
。
假设 第 k次随便随便选一层扔 ,选第 层 碎了,那么只好 碎了我也有2部手机不是,
那么 我此时想用两部手机测出(+1)~( -1)范围的耐摔指数就和上面情况一样的
最坏测试次数满足关系 k(k+1)/2>=( -1)-( +1)=- -1(同时保证 k+1+1….+1 <=K,===>k<=K-K注 :这是大 K)
如法炮制 但是这里的小k 每行是不一样的所以要将他们 用大K 替换掉
k(k+1)/2>=-1= -1 k<=K-1
k(k+1)/2>=( -1)- =- -1 k<=K-2
k(k+1)/2>=( -1)- =- -1 k<=K-3
……
k(k+1)/2>=( -1)- =- -1 k<=K-K
替换后:
(K-1)K/2>=-1= -1
(K-2)(K-1)/2>=( -1)- =- -1
(K-3)(K-2)/2>=( -1)- =- -1
……
(K-K)(K-(K-1))/2>=( -1)- =- -1
消消元: 1/2 [(K-1)K+ (K-2)(K-1)+(K-3)(K-2)……(K-K)(K-(K-1))]>=-K
配凑法: 1/2 [k^2+(K-1)^2+ (K-2)^2+(K-3)^2……(K-(k-1))^2]-[K+(K-1)+(K-2)+(k-3)……+(K-(K-1))]>=-K
(同时增加减少 [K+(K-1)+(K-2)……(K-(K-1))]- [K+(K-1)+(K-2)……(K-(K-1))+(K-K)] )
两边化简一下:1/2 [K^2+(K-1)^2+ (K-2)^2+(K-3)^2……1^2]-[K+(K-1)+(K-2)+(k-3)……+(K-(K-1))+(K-K)]>=-K
===>1/2 [K^2+(K-1)^2+ (K-2)^2+(K-3)^2……1^2]-[K(K+1)-1-2-3…..-K]>=-K
根据平方求和公式 :
所以 原式等于 1/2{ K(K+1)(2K+1)/6 -[K(K+1)-K(K+1)/2]>=-K
====>1/2{ K(K+1)(2K+1)/6 -[K(K+1)-K(K+1)/2]>=-K
====> (K^3+5K)/6 >= ==1000
====> K=19
于是就得到了 公式
如此类推 可以得到其4部手机 5部 手机等
代码 就随便写了
#include<stdio.h>int main(){ int i; for(i=0;i<100;i++) if((i*i*i+i*5)/6>=1000)break; printf("%d\n",i); return 0;}
]]>
核心代码:
import java.awt.*;import javax.swing.*;import java.awt.event.*;import java.util.*;//游戏运行入口public class FiveChess{public static void main(String[] args){new FiveChessMenu();}}//界面类,这是游戏主体框架class FiveChessWindows extends JFrame {//五子棋窗口 private Chessboard chessboard = new Chessboard();//五子棋盘【关键】 private Chess chess = new Chess(); //五子棋业务逻辑【关键】 private Panel toolbar1,toolbar2,toolbar3; private boolean flag;// private JButton startButton; private JTextField text1, text2,text3,text4; private JButton prompt1,prompt2; private JButton backButton1,backButton2; private JButton exitButton; private int owner_flag=1;//用于左右互搏 private boolean prompt_flag=false; private String utf_hz = null,utf_bz=null; // //完成五子棋游戏界面 public void init(Boolean flag,int res_flag){ this.flag=flag;Chess.FIRST=res_flag; setTitle("java版五子棋-five");//创建游戏界面窗口 toolbar1 = new Panel(); toolbar2 = new Panel(); toolbar3 = new Panel(); toolbar1.setLayout(new GridLayout(3,1,20,20)); toolbar3.setLayout(new GridLayout(3,1,20,20)); text1 = new JTextField(); text1.setPreferredSize(new Dimension(60, 60)); // 设置大小 text1.setFont(new Font(null, Font.BOLD,50)); text1.setEditable(false);//设置不可编辑 text2 = new JTextField(); text2.setPreferredSize(new Dimension(60, 60)); // 设置大小 text2.setFont(new Font(null, Font.BOLD,50)); text2.setEditable(false);//设置不可编辑 text3 = new JTextField(); text3.setPreferredSize(new Dimension(60, 60)); // 设置大小 text3.setFont(new Font(null, Font.BOLD,50)); text3.setEditable(false);//设置不可编辑 text4 = new JTextField(); text4.setPreferredSize(new Dimension(60, 60)); // 设置大小 text4.setFont(new Font(null, Font.BOLD,50)); text4.setEditable(false);//设置不可编辑 //把“选项”菜单加入到菜单栏 //MyButton startButton= new MyButton(" 重 新 开 始 "); startButton = new MyButton(" 重 新 开 始 "); backButton1 = new MyButton(" 悔 棋 "); backButton2 = new MyButton(" 悔 棋 "); prompt1 = new MyButton(" 提 ? 示 "); prompt2 = new MyButton(" 提 ? 示 "); exitButton = new MyButton(" 返 回 菜 单 "); toolbar1.setBackground(Color.cyan); toolbar2.setBackground(Color.green); toolbar3.setBackground(Color.cyan); if(!flag)toolbar1.add(new JLabel(new ImageIcon("./src/玩家.png"))); else toolbar1.add(new JLabel(new ImageIcon("./src/电脑1.png"))); toolbar3.add(new JLabel(new ImageIcon("./src/玩家.png"))); JPanel j3 =new JPanel(new GridLayout(2,1,5,5)); j3.add(text1);j3.add(text3); toolbar1.add(j3); if(!flag)text1.setText("—玩 家—"); else text1.setText("—电 脑—"); JPanel j4 =new JPanel(new GridLayout(2,1,5,5)); j4.add(text2);j4.add(text4); toolbar3.add(j4); text2.setText("—玩 家—"); JPanel j1=new JPanel(); j1.setLayout(new GridLayout(3,1,20,20)); j1.setBackground(Color.cyan); j1.add(prompt1); j1.add(backButton1); toolbar1.add(j1); JPanel j2=new JPanel(); j2.setLayout(new GridLayout(3,1,20,20));//网格布局 j2.setBackground(Color.cyan); j2.add(prompt2); j2.add(backButton2); toolbar3.add(j2); exitButton.setSize(180, 60); toolbar2.add(startButton); toolbar2.add(exitButton); Gbk_Utf1(); textInit(); ButtonInit();//按钮事件绑定初始化 add(toolbar1, BorderLayout.WEST); add(toolbar2, BorderLayout.SOUTH); add(toolbar3, BorderLayout.EAST); add(chessboard,BorderLayout.CENTER);//把五子棋盘加入到frame //绑定鼠标事件,要下棋了,为了避免写无用的抽象方法的实现, chessboard.addMouseListener(new MouseAdapter(){ public void mouseClicked(MouseEvent e){ play(e);//鼠标点击引发下棋事件,处理下棋事件比较繁琐,为此开一个方法 } }); //设置frame窗口左上角图标 setIconImage(this.getToolkit().getImage("./src/favicon.png")); setLocation(225, 100); setSize(1198, 800); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(false); setVisible(true); AIFirstOptionInit();// } public void ButtonInit() { backButton1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int xy=chessboard.goback(); if(xy>0)chess.goback(xy); } }); backButton2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // goback(); int xy=chessboard.goback(); if(xy>0)chess.goback(xy); } }); prompt1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { prompt_flag=!prompt_flag; chessboard.setPrompt(prompt_flag); if(prompt_flag) chessboard.setScores(chess.getScores()); chessboard.repaint(); <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> prompt2<span class="token punctuation">.</span><span class="token function">addActionListener</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ActionListener</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">actionPerformed</span><span class="token punctuation">(</span>ActionEvent e<span class="token punctuation">)</span> <span class="token punctuation">{</span> prompt_flag<span class="token operator">=</span><span class="token operator">!</span>prompt_flag<span class="token punctuation">;</span> chessboard<span class="token punctuation">.</span><span class="token function">setPrompt</span><span class="token punctuation">(</span>prompt_flag<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>prompt_flag<span class="token punctuation">)</span> <span class="token punctuation">{</span>chessboard<span class="token punctuation">.</span><span class="token function">setScores</span><span class="token punctuation">(</span>chess<span class="token punctuation">.</span><span class="token function">getScores</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> chessboard<span class="token punctuation">.</span><span class="token function">repaint</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> exitButton<span class="token punctuation">.</span><span class="token function">addActionListener</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ActionListener</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">actionPerformed</span><span class="token punctuation">(</span>ActionEvent e<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">new</span> <span class="token class-name">FiveChessMenu</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">dispose</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> startButton<span class="token punctuation">.</span><span class="token function">addActionListener</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ActionListener</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">actionPerformed</span><span class="token punctuation">(</span>ActionEvent e<span class="token punctuation">)</span> <span class="token punctuation">{</span> FiveChessWindows five <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FiveChessWindows</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> five<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>flag<span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">new</span> <span class="token class-name">RockPaperScissors</span><span class="token punctuation">(</span>flag<span class="token punctuation">,</span>five<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">dispose</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token comment" spellcheck="true">//“先后手处理事件</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">AIFirstOptionInit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment" spellcheck="true">//棋盘还没有落子的时候可以选择“机器先手”,一旦有落子,选择“机器先手”失效</span> <span class="token keyword">if</span><span class="token punctuation">(</span>chessboard<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>Chess<span class="token punctuation">.</span>FIRST <span class="token operator">==</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">//机器先手,则先在中间位置下一个棋子</span> chessboard<span class="token punctuation">.</span><span class="token function">addChessman</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> chess<span class="token punctuation">.</span><span class="token function">addChessman</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>
}
public void Gbk_Utf1() {
try {
utf_hz= new String("⚫".getBytes("UTF-8"), "UTF-8");
utf_bz = new String("⚪".getBytes("UTF-8"), "UTF-8");
} catch (UnsupportedEncodingException e1) {e1.printStackTrace();}
}
public void textInit() {
if(Chess.FIRST==-1) {text3.setText(" 先手"+utf_hz);text4.setText(" 后手 "+utf_bz);}
else {text3.setText(" 后手 "+utf_bz);text4.setText(" 先手 "+utf_hz);}
}
//核心业务逻辑 处理鼠标落子事件
public void play(MouseEvent e){
int cellSize = chessboard.getCellSize();//每个格子的边长
int x = (e.getX() - 5) / cellSize;//像素值转换成棋盘坐标
int y = (e.getY() - 5) / cellSize;//像素值转换成棋盘坐标
//判断落子是否合法
boolean isLegal = chess.isLegal(x, y);
//如果落子合法
if(isLegal){
chessboard.addChessman(x, y, owner_flag);//界面方面加一个棋子
chess.addChessman(x, y, owner_flag);//逻辑业务方面加一个棋子
//判断人类是否胜利
if(chess.isWin(x, y, owner_flag)){
chessboard.setIsWin(chess.getisWinChess());
JOptionPane.showMessageDialog(this, " 己方获胜", "您赢了!", JOptionPane.PLAIN_MESSAGE);
chessboard.init();//初始化
chess.init();
textInit();
return;
}
Location loc = chess.searchLocation();//根据五元贡献的方法确定
if(flag) {
//机器落子
//Location loc = chess.searchLocation();//根据五元贡献的方法确定
chessboard.addChessman(loc);
chess.addChessman(loc.getX(), loc.getY(), loc.getOwner());
//判断机器是否胜利
if(chess.isWin(loc.getX(), loc.getY(), -1)){
chessboard.setIsWin(chess.getisWinChess());
JOptionPane.showMessageDialog(this, " 对方获胜", "您输了!", JOptionPane.PLAIN_MESSAGE);
chessboard.init();
chess.init();
textInit();
return;
}
}else owner_flag=-owner_flag;
chessboard.setPrompt(prompt_flag);//更行提示分数和棋子
chess.searchLocation();chessboard.setScores(chess.getScores());
}
}
}
class Chessboard extends JPanel{//棋盘类 继承了 JPanel
private static final long serialVersionUID = 1L;
public static final int CHESSBOARD_SIZE = 15;//棋盘大小15X15
private ArrayList locationList = new ArrayList();//棋盘上所有可以落子的位置坐标等信息
private Color backgroundColor = new Color(255, 245, 186);//棋盘背景色
private Color lineColor = new Color(66, 66, 66);//棋盘线条颜色
private int margin = 30;//棋盘边缘长度
private int[][] scores;//获取胜利棋子;
private int[] iswinxy;
private boolean prompt_flag=false;
public void init(){locationList.clear();repaint();} //初始化棋盘
public void setPrompt(boolean prompt_flag2) {this.prompt_flag=prompt_flag2;}//获取是否提示状态
public void setScores(int[][] scores) {this.scores=scores;}//获取分数数据
public void setIsWin(int[] iswinxy) {this.iswinxy=iswinxy;}
public void paint(Graphics g){//覆盖paint方法
super.paint(g);
drawChessboard(g);//画棋盘
drawScores(g);//画分数
drawiswin(g);//画胜利棋子
drawChessman(g);//画棋子
}
public void drawChessboard(Graphics g){//画棋盘
g<span class="token punctuation">.</span><span class="token function">setColor</span><span class="token punctuation">(</span>backgroundColor<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//先画背景</span> g<span class="token punctuation">.</span><span class="token function">fillRect</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getHeight</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> g<span class="token punctuation">.</span><span class="token function">setColor</span><span class="token punctuation">(</span>lineColor<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//画线</span> <span class="token keyword">int</span> cellSize <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">2</span><span class="token operator">*</span>margin<span class="token punctuation">)</span><span class="token operator">/</span><span class="token punctuation">(</span>CHESSBOARD_SIZE <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//每个格子的边长</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> CHESSBOARD_SIZE<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> g<span class="token punctuation">.</span><span class="token function">drawLine</span><span class="token punctuation">(</span>margin<span class="token punctuation">,</span> margin <span class="token operator">+</span> i<span class="token operator">*</span>cellSize<span class="token punctuation">,</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> margin<span class="token punctuation">,</span> margin <span class="token operator">+</span> i<span class="token operator">*</span>cellSize<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//画横线</span> g<span class="token punctuation">.</span><span class="token function">drawLine</span><span class="token punctuation">(</span>margin <span class="token operator">+</span> i<span class="token operator">*</span>cellSize<span class="token punctuation">,</span> margin<span class="token punctuation">,</span> margin <span class="token operator">+</span> i<span class="token operator">*</span>cellSize<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getHeight</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span>margin<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//画纵线</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">drawChessman</span><span class="token punctuation">(</span>Graphics g<span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token comment" spellcheck="true">//画棋子</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> locationList<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> Location loc <span class="token operator">=</span> locationList<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> cellSize <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">2</span><span class="token operator">*</span>margin<span class="token punctuation">)</span><span class="token operator">/</span><span class="token punctuation">(</span>CHESSBOARD_SIZE <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//每个格子的边长</span> <span class="token keyword">if</span><span class="token punctuation">(</span>i<span class="token operator">==</span>locationList<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> g<span class="token punctuation">.</span><span class="token function">setColor</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Color</span><span class="token punctuation">(</span><span class="token number">207</span><span class="token punctuation">,</span><span class="token number">13</span><span class="token punctuation">,</span><span class="token number">62</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">// 标记最后一个棋子四周为红色</span> g<span class="token punctuation">.</span><span class="token function">fillRoundRect</span><span class="token punctuation">(</span>margin <span class="token operator">+</span> cellSize<span class="token operator">*</span>loc<span class="token punctuation">.</span><span class="token function">getX</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cellSize<span class="token operator">/</span><span class="token number">2</span><span class="token operator">-</span><span class="token number">5</span><span class="token punctuation">,</span> margin <span class="token operator">+</span> cellSize<span class="token operator">*</span>loc<span class="token punctuation">.</span><span class="token function">getY</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cellSize<span class="token operator">/</span><span class="token number">2</span><span class="token operator">-</span><span class="token number">5</span><span class="token punctuation">,</span> cellSize<span class="token operator">+</span><span class="token number">8</span><span class="token punctuation">,</span> cellSize<span class="token operator">+</span><span class="token number">8</span><span class="token punctuation">,</span><span class="token number">100</span><span class="token punctuation">,</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> g<span class="token punctuation">.</span><span class="token function">setColor</span><span class="token punctuation">(</span>backgroundColor<span class="token punctuation">)</span><span class="token punctuation">;</span> g<span class="token punctuation">.</span><span class="token function">fillRoundRect</span><span class="token punctuation">(</span>margin <span class="token operator">+</span> cellSize<span class="token operator">*</span>loc<span class="token punctuation">.</span><span class="token function">getX</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cellSize<span class="token operator">/</span><span class="token number">2</span><span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> margin <span class="token operator">+</span> cellSize<span class="token operator">*</span>loc<span class="token punctuation">.</span><span class="token function">getY</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cellSize<span class="token operator">/</span><span class="token number">2</span><span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> cellSize<span class="token operator">+</span><span class="token number">2</span><span class="token punctuation">,</span> cellSize<span class="token operator">+</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">100</span><span class="token punctuation">,</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">//根据先后手设置棋子为黑色和白色</span> <span class="token keyword">if</span><span class="token punctuation">(</span>loc<span class="token punctuation">.</span><span class="token function">getOwner</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> Chess<span class="token punctuation">.</span>FIRST<span class="token punctuation">)</span>g<span class="token punctuation">.</span><span class="token function">setColor</span><span class="token punctuation">(</span>Color<span class="token punctuation">.</span>BLACK<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> g<span class="token punctuation">.</span><span class="token function">setColor</span><span class="token punctuation">(</span>Color<span class="token punctuation">.</span>WHITE<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//画棋子</span> g<span class="token punctuation">.</span><span class="token function">fillOval</span><span class="token punctuation">(</span>margin <span class="token operator">+</span> cellSize<span class="token operator">*</span>loc<span class="token punctuation">.</span><span class="token function">getX</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cellSize<span class="token operator">/</span><span class="token number">2</span><span class="token operator">+</span><span class="token number">3</span><span class="token punctuation">,</span> margin <span class="token operator">+</span> cellSize<span class="token operator">*</span>loc<span class="token punctuation">.</span><span class="token function">getY</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cellSize<span class="token operator">/</span><span class="token number">2</span><span class="token operator">+</span><span class="token number">3</span><span class="token punctuation">,</span> cellSize<span class="token operator">-</span><span class="token number">6</span><span class="token punctuation">,</span> cellSize<span class="token operator">-</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>
//划分数
public void drawScores(Graphics g) {
if(prompt_flag) {
int Maxscore=0,Maxx=-1,Maxy=-1;
g.setColor(Color.darkGray);
int cellSize = (this.getWidth() - 2*margin)/(CHESSBOARD_SIZE - 1);//每个格子的边长
for(int i = 0; i < CHESSBOARD_SIZE; i++)
for(int j = 0; j < CHESSBOARD_SIZE; j++) {
if(Maxscore<=scores[i][j]){Maxscore=scores[i][j];Maxx=i;Maxy=j;}
g.drawString(""+scores[i][j],margin + i*cellSize, margin + j*cellSize);
}
g.setColor(Color.green);//画提示棋子。
g.fillOval(margin + cellSize*Maxx - cellSize/2+5, margin + cellSize*Maxy - cellSize/2+5, cellSize-8, cellSize-8);
}
}
public void drawiswin(Graphics g) { //画胜利棋子
if(iswinxy!=null && iswinxy.length>3) {
g.setColor(Color.darkGray);System.out.println(iswinxy.length);
int cellSize = (this.getWidth() - 2*margin)/(CHESSBOARD_SIZE - 1);//每个格子的边长
int x1,y1;
for(int i=0;i<5;i++) {
x1=iswinxy[i]/100;y1=iswinxy[i]%100;
g.setColor(new Color(207,13,62));//
g.fillRoundRect(margin + cellSize*x1 - cellSize/2-5, margin + cellSize*y1 - cellSize/2-5, cellSize+8, cellSize+8,100,100);
g.setColor(backgroundColor);
g.fillRoundRect(margin + cellSize*x1 - cellSize/2-2, margin + cellSize*y1 - cellSize/2-2, cellSize+2, cellSize+2,100,100);
}
iswinxy=null;
}
}
public int goback() {
if (locationList.size() == 0)return -1;
int x=locationList.get(locationList.size()-1).getX();
int y=locationList.get(locationList.size()-1).getY();
locationList.remove(locationList.size()-1);repaint();
return x*100+y;
}
public void addChessman(int x, int y, int owner){locationList.add(new Location(x, y, owner));repaint();}//落子
public void addChessman(Location loc){locationList.add(loc);repaint();}
public int getCellSize(){return (this.getWidth() - 2*margin)/(CHESSBOARD_SIZE - 1);}//计算棋盘每个小格子的大小
public boolean isEmpty() {return locationList.size() == 0 ? true : false;}//判断棋盘是否还没有棋子
}
class Location{
private int x;//某个棋盘位置横坐标,0-14
private int y;//某个棋盘位置纵坐标,0-14
private int owner;//占据该位置的棋手方,1是人类,-1是机器,0是空
private int score;//对该位置的打的分数
public Location(){}//构造方法
public Location(int x, int y, int owner){this.x = x;this.y = y;this.owner = owner;}
public Location(int x, int y, int owner, int score){this(x, y, owner);this.score = score;}
public int getX(){return this.x;}//x 坐标
public void setX(int x){this.x = x;}
public int getY(){return this.y;} //y坐标
public void setY(int y){this.y = y;}
public int getOwner(){return this.owner;}// 棋盘点 状态坐标
public void setOwner(int owner){this.owner = owner;}
public int getScore(){return this.score;}// 该点分数
public void setScore(int score){this.score = score;}
}
//下棋业务核心类,与界面棋盘对应,业务放在这里,可以和界面代码分离
class Chess{
public static final int CHESSBOARD_SIZE = 15;
public static int FIRST = 1;//先手,-1表示机器,1表示人类,与Location类中的对应
private int[][] chessboard = new int[CHESSBOARD_SIZE][CHESSBOARD_SIZE];//与界面棋盘对应,0代表空,-1代表机器,1代表人类
private int[][] score = new int[CHESSBOARD_SIZE][CHESSBOARD_SIZE];//每个位置得分
private int[] iswinxy=new int[6];//胜利棋子坐标。
public Chess(){}
public void goback(int xy) {chessboard[xy/100][xy%100]=0;}
public void init(){
FIRST = 1;//默认人类先手
for(int i = 0; i < CHESSBOARD_SIZE; i++)
for(int j = 0; j < CHESSBOARD_SIZE; j++){chessboard[i][j] = 0; score[i][j] = 0;}//初始化棋盘 和分数表
}
public void addChessman(int x, int y, int owner){chessboard[x][y] = owner;} //落子
public boolean isLegal(int x, int y){//棋盘边界判断 以及是否落子 //判断落子位置是否合法
if(x >=0 && x = 0 && y < CHESSBOARD_SIZE && chessboard[x][y] == 0)return true;
return false;
}
public boolean isWin(int x, int y, int owner){//判断哪方赢了(必定有刚落的子引发,因此只需判断刚落子的周围),owner为-1代表机器,owner为1代表人类
int sum = 0,k=1; for(int i=0;i<6;i++)iswinxy[i]=0;
iswinxy[0]=x*100+y;
//判断纵向上下方向
for(int i = x - 1; i >= 0; i–)if(chessboard[i][y] == owner){ sum++;iswinxy[k++]=i*100+y;}else break;
for(int i = x + 1; i < CHESSBOARD_SIZE; i++)if(chessboard[i][y] == owner){sum++;iswinxy[k++]=i*100+y;}else break;
if(sum >= 4) {return true;}
//判断横向向左右边
sum = 0;k=1;
for(int i = y - 1; i >= 0; i–)if(chessboard[x][i] == owner){sum++;iswinxy[k++]=x*100+i;}else break;
for(int i = y + 1; i < CHESSBOARD_SIZE; i++)if(chessboard[x][i] == owner){sum++;iswinxy[k++]=x*100+i;}else break;
if(sum >= 4) {return true;}
//判断左上角到右下角方向上侧和左上角到右下角方向下侧(正斜线)
sum = 0;k=1;
for(int i = x - 1, j = y - 1; i >= 0 && j >= 0; i–, j– )if(chessboard[i][j] == owner){sum++;iswinxy[k++]=i*100+j;}else break;
for(int i = x + 1, j = y + 1; i < CHESSBOARD_SIZE && j < CHESSBOARD_SIZE; i++, j++ )if(chessboard[i][j] == owner){sum++;iswinxy[k++]=i*100+j;}else break;
if(sum >= 4) {return true;}
//判断右上角到左下角方向上侧和右上角到左下角方向下侧(反斜线)
sum = 0;k=1;
for(int i = x + 1, j = y - 1; i = 0; i++, j–)if(chessboard[i][j] == owner){sum++;iswinxy[k++]=i*100+j;}else break;
for(int i = x - 1, j = y + 1; i >= 0 && j < CHESSBOARD_SIZE; i–, j++ )if(chessboard[i][j] == owner){sum++;iswinxy[k++]=i*100+j;}else break;
if(sum >= 4) {return true;}
return false;
}
public int[] getisWinChess() { return iswinxy;}//获取胜利棋子
public int[][] getchessborad() { return chessboard;}//获取胜利棋子
//确定机器落子位置
//使用五元贡献评分算法
//算法思路:对15X15的572个五元组分别评分,一个五元组的得分就是该五元组为其中每个位置贡献的分数, 一个位置的分数就是其所在所有五元组分数之和。所有空位置中分数最高的那个位置就是落子位置。
public Location searchLocation(){
int humanChessmanNum = 0;//五元组中的黑棋数量
int machineChessmanNum = 0;//五元组中的白棋数量
int tupleScoreTmp = 0;//五元组得分临时变量
int goalX = -1;//目标位置x坐标
int goalY = -1;//目标位置y坐标
int maxScore = -1;//最大分数
for(int i = 0; i < CHESSBOARD_SIZE; i++)//每次都初始化下score评分数组(全部置零)////每次机器找寻落子位置,评分都重新算一遍
for(int j = 0; j < CHESSBOARD_SIZE; j++) score[i][j] = 0;
//1.扫描横向和横向的15个行
for(int i = 0; i < CHESSBOARD_SIZE; i++){
for(int j = 0; j < CHESSBOARD_SIZE-4; j++){
for(int k = j; k < j + 5; k++)//每次加五个状态
if(chessboard[i][k] == -1) machineChessmanNum++;else if(chessboard[i][k] == 1)humanChessmanNum++;
tupleScoreTmp = tupleScore(humanChessmanNum, machineChessmanNum);//为该五元组的每个位置添加分数
for(int k = j; k < j + 5; k++)score[i][k] += tupleScoreTmp;
humanChessmanNum =tupleScoreTmp=machineChessmanNum=0;//清零
for(int k = j; k < j + 5; k++){//每次加五个状态
if(chessboard[k][i] == -1) machineChessmanNum++;
else if(chessboard[k][i] == 1)humanChessmanNum++;
}
tupleScoreTmp = tupleScore(humanChessmanNum, machineChessmanNum);
for(int k = j; k < j + 5; k++)score[k][i] += tupleScoreTmp;
humanChessmanNum =tupleScoreTmp=machineChessmanNum=0;//清零
}
}
//3.扫描右上角到左下角上侧部分
for(int i = CHESSBOARD_SIZE-1; i >= 4; i–){
for(int k = i, j = 0; j = 0; j++, k–){
int m = k, n = j;
while(m > k - 5 && k - 5 >= -1){
if(chessboard[m][n] == -1) machineChessmanNum++;
else if(chessboard[m][n] == 1)humanChessmanNum++;
m–;n++;
}
if(m == k-5){//注意斜向判断的时候,可能构不成五元组(靠近四个角落),遇到这种情况要忽略掉
tupleScoreTmp = tupleScore(humanChessmanNum, machineChessmanNum);
for(m = k, n = j; m > k - 5 ; m–, n++)score[m][n] += tupleScoreTmp;//为该五元组的每个位置添加分数
}
humanChessmanNum =tupleScoreTmp=machineChessmanNum=0;//清零
}
}
//4.扫描右上角到左下角下侧部分
for(int i = 1; i < CHESSBOARD_SIZE; i++){
for(int k = i, j = CHESSBOARD_SIZE-1; j >= 0 && k < CHESSBOARD_SIZE; j–, k++){
int m = k,n=j;
while(m < k + 5 && k + 5 <= CHESSBOARD_SIZE){
if(chessboard[n][m] == -1) machineChessmanNum++;
else if(chessboard[n][m] == 1)humanChessmanNum++;
m++;n–;
}
if(m == k+5){//注意斜向判断的时候,可能构不成五元组(靠近四个角落),遇到这种情况要忽略掉
tupleScoreTmp = tupleScore(humanChessmanNum, machineChessmanNum);
for(m = k, n = j; m < k + 5; m++, n–)score[n][m] += tupleScoreTmp;//为该五元组的每个位置添加分数
}
humanChessmanNum =tupleScoreTmp=machineChessmanNum=0;//清零
}
}
//5.扫描左上角到右下角部分
for(int i = 0; i < CHESSBOARD_SIZE-4; i++){
for(int k = i, j = 0; j < CHESSBOARD_SIZE && k < CHESSBOARD_SIZE; j++, k++){
int m,n;
for(m=k,n=j;m < k + 5 && k + 5 <= CHESSBOARD_SIZE;m++,n++){
if(chessboard[m][n] == -1) machineChessmanNum++;
else if(chessboard[m][n] == 1)humanChessmanNum++;
}
if(m == k + 5){//注意斜向判断的时候,可能构不成五元组(靠近四个角落),遇到这种情况要忽略掉
tupleScoreTmp = tupleScore(humanChessmanNum, machineChessmanNum);
for(m = k, n = j; m < k + 5; m++, n++)score[m][n] += tupleScoreTmp; //为该五元组的每个位置添加分数
}
humanChessmanNum =tupleScoreTmp=machineChessmanNum=0;//清零
for(m=k,n=j;m < k + 5 && k + 5 <= CHESSBOARD_SIZE;m++,n++){
if(chessboard[n][m] == -1) machineChessmanNum++;
else if(chessboard[n][m] == 1)humanChessmanNum++;
}
if(m == k + 5){//注意斜向判断的时候,可能构不成五元组(靠近四个角落),遇到这种情况要忽略掉
tupleScoreTmp = tupleScore(humanChessmanNum, machineChessmanNum);
//为该五元组的每个位置添加分数
for(m = k, n = j; m < k + 5; m++, n++)score[n][m] += tupleScoreTmp;
}
humanChessmanNum =tupleScoreTmp=machineChessmanNum=0;//清零
}
}
for(int i = 0; i < CHESSBOARD_SIZE; i++)//从空位置中找到得分最大的位置(确定落子位置)
for(int j = 0; j < CHESSBOARD_SIZE; j++)
if(chessboard[i][j] == 0 && score[i][j] > maxScore){goalX = i; goalY = j; maxScore = score[i][j];}
else if(chessboard[i][j] != 0)score[i][j]=0;
if(goalX != -1 && goalY != -1)return new Location(goalX, goalY, -1);
return new Location(-1, -1, -1);//没找到坐标说明平局了
}
public int[][] getScores() {return score;}
//各种五元组情况评分表
public int tupleScore(int humanChessmanNum, int machineChessmanNum){
int[] hb= {0,15,400,1800,100000};//人类落子 1,2,3,4 分别对应 15 400 1800,100000
int[] mb= {0,35,800,15000,800000};//机器落子 1,2,3,4分别对应 35 800 15000 800000
//1.既有人类落子,又有机器落子,判分为0
if(humanChessmanNum > 0 && machineChessmanNum > 0)return 0;
if(humanChessmanNum == 0 && machineChessmanNum == 0)return 7;
if(machineChessmanNum >0)return mb[machineChessmanNum];
if(humanChessmanNum>0)return hb[humanChessmanNum];
return -1;//若是其他结果肯定出错了。这行代码根本不可能执行
}
}
//自定义按钮
class MyButton extends JButton {
private Color quit = new Color(205, 255, 205);// 离开时颜色
public static final Color BUTTON_COLOR1 = new Color(205, 255, 205);
public static final Color BUTTON_COLOR2 = new Color(51, 154, 47);
public MyButton(String s) {
super(s);
setFont(new java.awt.Font(null, 1, 22)); //
setBorder(BorderFactory.createRaisedBevelBorder());//凸出
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
setContentAreaFilled(false);// 是否显示外围矩形区域 选否
}
public void paintComponent(Graphics g) {
g.setColor(quit);
g.fillRoundRect(0, 0, getSize().width - 1, getSize().height - 1,20, 20);
super.paintComponent(g);
}
public void paintBorder(Graphics g) { g.drawRoundRect(0, 0, getSize().width - 1, getSize().height - 1,20, 20);}
}
1 主菜单页面展示
2 猜拳决定落子展示
3.下棋展示(当前落子圈红)
4.获胜突出现实展示
5.开启提示展示(绿色提示落子)
完整资源链接: 下载链接
]]>综合程序设计案例一:导弹追踪问题
设位于坐标原点的甲舰向位于x轴上点A(10, 20)处的乙舰发射导弹,导弹头始终对准乙舰。如果乙舰以最大的速度v0(是常数)行驶,行驶轨迹满足曲线方程y=-4x^2+80x+20,导弹的速度是20v0,绘图表示导弹和乙舰行驶轨迹的曲线方程,并标注图形说明。
思路:将模块离散化 每一小段近似为直线,通过 斜率 按比例预计算
示意绘图
结果:
结论: 上图为结果 以乙船速度V 为 单位1 计算 经过 1.1713 后被击中 被击中时的坐标点为 (10.0147 ,21.1712)
实现代码:
%思路: 将模型离散化,每一小段近似为直线 function main x=10:0.0000001:10.05;%乙船 x方向运动 y=-4*(x-10).^2+80*(x-10)+20;%乙船 y方向运动 [x1,y1,sum_L,goal]=myf(x,y,20);%自定义函数预测导弹轨迹 plot(x,y,'r.')%打印乙船曲线 axis([0,15,0,24]); hold on; plot(x1,y1,'b-')%打印导弹曲线 t=sum_L/1.0%击中时间 x(goal)%击中x点 y(goal)%击中y点 plot(x(goal),y(goal),'g*')%打印标记击中点 legend('乙船轨迹','导弹轨迹','击中点'); end function [x1,y1,sum_L,goal]=myf(x,y,Vb)%已知乙船的运动轨迹,速度倍速Vb x1=[];%导弹 x方向运动 y1=[];%导弹 y方向运动 x1(1)=0;%导弹 x 初始坐标 y1(1)=0;%导弹 y 初始坐标 sum_L=0;%乙船总路程 goal=0;%击中目标点索引 for i=2:length(x)% 通过已知轨迹计算导弹轨迹 L=sqrt((x(i)-x(i-1))^2+(y(i)-y(i-1))^2);%乙船运动距离通过公式 根号(x^2+y^2) sum_L=sum_L+L;%更新乙船总路程 通过斜率 x1(i)=x1(i-1)+Vb*L*(x(i)-x1(i-1)) /sqrt((x(i)-x1(i-1))^2+(y(i)-y1(i-1))^2);%求导弹下一个位子x1值 y1(i)=y1(i-1)+Vb*L*(y(i)-y1(i-1))/sqrt((x(i)-x1(i-1))^2+(y(i)-y1(i-1))^2);%求导弹下一个位子y1值 if(x1(i)>=x(i)) goal=i; break;end endend
时间限制: 1Sec 内存限制: 128MB 提交: 40 解决: 7
题目描述
古时丧葬活动中经常请高僧做法事。仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。
节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示N级浮屠)。又有若干小和尚随机地“站”在某个台阶上。最高一级台阶必须站人,其它任意。(如图1所示)
两位参加游戏的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。两个小和尚也不能站在同一台阶,也不能向低级台阶移动。
两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。
对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。
输入
输入数据为一行用空格分开的N个整数,表示小和尚的位置。台阶序号从1算起,所以最后一个小和尚的位置即是台阶的总数。(N< 100, 台阶总数< 1000)
输出
输出为一行用空格分开的两个整数: A B, 表示把A位置的小和尚移动到B位置。若有多个解,输出A值较小的解,若无解则输出-1。
样例输入
1 5 9
样例输出
1 4
这是一道经典的阶梯Nim博弈问题,想解决这道题 首先要知道Nim博弈(如果知道就直接看代码吧), Nim博弈就是说,给你几堆小石子 ,让两个玩家分别在这几堆小石子中取出石子(可以将某堆石子全部取出 也可以在某堆中只取一个小石子,当然是不可能不取的,不然还玩撒)。谁取到最后 ,没有石子取就输了。
比如 有 3 堆石子 ,每堆分别为 2 3 4个小石子,如下图所示
玩游戏都想赢 ,所以 如何取尤为重要,方案有很多,想快速知道如果我方先手 是赢 还是输,直接就用Nim 研究过的成果。
Nim 的做法 就是 将 2 3 4 都转化为2进制再 异或 得出结果,如果结果是非0 那么先手必定赢 如果结果为0 那么先手必输(前提,玩游戏的都想赢 且都很聪明)
可以看到异或后得到的结果是非0 则先手必胜, 先手遇到如此局面肯定会想办法 将它 变成0 这里先手在个数为4的一堆中取出3个。这堆就变成1个 整个局面的结果 就变成0,那么后手进行操作的话,无论操作 哪一堆,在哪堆中拿多少个石子,看看下图对不对。 肯定会破坏这种局面,让结果变为非0,比如后手在为3堆一堆取走3,
比如后手在为3堆一堆取走3,如下图
现在又到该先手取石子了,这个时候先手肯定要把 2个石子的一堆取出1个来,还剩1个,如图所示
现在又轮到 后手去取石子,现在一眼就可以看出 先手必赢了吧, 后手根据规则 只能拿走一个,然后轮到先手 拿了最后一个,后手就没得办法取 ,游戏就结束了。
现在回过头来 看阶梯Nim博弈问题。 只需要将 阶梯Nim博弈问题转换为Nim博弈问题即可,做如下转换,每两个和尚之间看做一堆,比如 和尚分别站 1 3 5 8 那么可以转换为3堆,分别为 1 1 2,再取异或 就可以知道 先手是否必赢,具体实现可以看代码。(注意; 如果移动了一个小和尚 除了边界 ,会影响相邻两堆的情况,看代码注释)
##AC代码
]]>#include<iostream>#define N 102using namespace std; int main(){ int a[N],b[N]; int n = 0,i,j,k,sum = 0; while(cin>>a[n])n++;//存储又有多少个小和尚 for(i=1; i<n; i++)b[i-1] = a[i] - a[i-1] - 1;// 进行Nim博弈的转换 for(i=0; i<n-1; i+=2) sum ^= b[i];//进行异或 if(sum==0)cout<<-1<<endl;//若开始局面为0 则必输 else//若非0 则必赢,因此 需要找到第一步 将局面变为0 的步骤 { for(i=0; i<n-1; ++i)//枚举移动第i堆 使得剩下的局面异或等于0, for(j=1; a[i]+j<a[i+1]; ++j) {//枚举可以移动的步数 保证 前项移动j 步后 不会超过后项 b[i] -= j;//拿走 j个 ,这里代表 前一个向上移动j步 if(i!=0)b[i-1] += j;//它的后一堆b[i]向取走了j个,那莫前一堆 b[i-1] 则要增加j个 第一堆除外 sum = 0; for(k=0; k<n-1; k+=2) sum ^= b[k];//重新计算局面, if(sum==0) {cout<<a[i]<<" "<<a[i]+j<<endl; break;}//若变成0 则后手必败,先手必赢。跳出即可; b[i] += j;//回溯 这不是必赢的操作 if(i!=0) b[i-1] -= j; } } return 0; }
废话不多说 ,分享一款酷炫的页面动态背景 效果见下图。
查看 demo
*{ margin: 0; padding: 0; } #canvas{ position: fixed; background: #ccc; overflow: auto; z-index: -1; }
<canvas id="canvas"></canvas>
<script> window.requestAnimationFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function( callback ){ window.setTimeout( callback, 1000/2 ); }; })(); var myCanvas = document.getElementById("canvas"); var ctx = myCanvas.getContext("2d");//getContext 设置画笔 var num; var w,h; var duixiang = []; var move = {}; function widthheight(){ w = myCanvas.width = window.innerWidth; h = myCanvas.height = window.innerHeight; num= Math.floor(w*h*0.00028);//点的数量。根据屏幕大小确定 for(var i = 0;i < num;i++){ duixiang[i] = { x:Math.random()*w, y:Math.random()*h, cX:Math.random()*0.6-0.3, cY:Math.random()*0.6-0.3, R:Math.floor(Math.random()*5)+2, //CC:Math.floor(Math.random()*3)+2, r: Math.floor(Math.random() * 254), g: Math.floor(Math.random() * 254), b:Math.floor(Math.random() * 254) } // console.log(duixiang[i]) Cricle(duixiang[i].x,duixiang[i].y,duixiang[i].R,duixiang[i].r,duixiang[i].g,duixiang[i].b); //Cricle(duixiang[i].x,duixiang[i].y,duixiang[i].R,duixiang[i].CC); } };widthheight();//获取浏览器的等宽度等高 function Cricle(x,y,R,r,g,b){ ctx.save();//保存路径 if(Math.random()>0.991) {ctx.globalAlpha= 0.9;}//ctx.fillStyle = "#CCC";}//填充的背景颜色 else { ctx.globalAlpha=0.47;} ctx.fillStyle = "rgb("+ r +","+ g +","+ b +")"; ctx.beginPath();//开始绘画 ctx.arc(x,y,R,Math.PI*2,0);//绘画圆 x y 半径(大小) 角度 一个PI 是180 * 2 = 360 真假 0/1 true/false ctx.closePath();//结束绘画 ctx.fill();//填充背景颜色 ctx.restore();//回复路径 };Cricle(); !function draw(){ ctx.clearRect(0,0,w,h)//先清除画布上的点 for(var i = 0;i < num;i++){ duixiang[i].x += duixiang[i].cX; duixiang[i].y += duixiang[i].cY; if(duixiang[i].x>w || duixiang[i].x<0){ duixiang[i].cX = -duixiang[i].cX; } if(duixiang[i].y>h || duixiang[i].y<0){ duixiang[i].cY = -duixiang[i].cY; } Cricle(duixiang[i].x,duixiang[i].y,duixiang[i].R,duixiang[i].r,duixiang[i].g,duixiang[i].b); //勾股定理判断两点是否连线 for(var j = i + 1;j < num;j++){ if( (duixiang[i].x-duixiang[j].x)*(duixiang[i].x-duixiang[j].x)+(duixiang[i].y-duixiang[j].y)*(duixiang[i].y-duixiang[j].y) <= 55*55 ){ line(duixiang[i].x,duixiang[i].y,duixiang[j].x,duixiang[j].y,0,i,j) } if(move.x){ if( (duixiang[i].x-move.x)*(duixiang[i].x-move.x)+(duixiang[i].y-move.y)*(duixiang[i].y-move.y) <= 100*100 ){ line(duixiang[i].x,duixiang[i].y,move.x,move.y,1,i,1) } } } } window.requestAnimationFrame(draw) }(); //绘制线条 function line(x1,y1,x2,y2,flag,i,j){ if (flag){var color = ctx.createLinearGradient(x1,y1,x2,y2); ctx.globalAlpha=0.5; color.addColorStop(0,"rgb("+ duixiang[i].r +","+ duixiang[i].g +","+ duixiang[i].b +")"); color.addColorStop(0.8,"#019ee5"); } else { var color = ctx.createLinearGradient(x1,y1,x2,y2); ctx.globalAlpha=0.9; color.addColorStop(0,"rgb("+ duixiang[i].r +","+ duixiang[i].g +","+ duixiang[i].b +")"); color.addColorStop(1,"rgb("+ duixiang[j].r +","+ duixiang[j].g +","+ duixiang[j].b +")"); } ctx.save(); ctx.strokeStyle = color; ctx.lineWidth = 0.5; ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke(); //ctx.restore(); } //document.onmousemove = function(e){ // move.x = e.clientX; // move.y = e.clientY; //} //console.log(move)//去掉注释 ,可以与背景互动 window.onresize = function(){ location.reload(); }</script>
#canvas1 { position: fixed; pointer-events:none;//鼠标多层响应事件 width: 100%; height: 100%; overflow: auto; z-index: 999; }
<canvas id="canvas1" style="whdth: 100%;height: 100%"></canvas>
<script>var _createClass = function () {function defineProperties(target, props) { for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}} return function (Constructor, protoProps, staticProps) {if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor;};}();function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}} var getRandom = function getRandom(min, max) { return Math.random() * (max - min) + min;};var getRandomInt = function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
};
var getRandomColor = function getRandomColor() {
var colors = [
‘rgba(231, 76, 60, 1)’, // red
‘rgba(241, 196, 15, 1)’, // yellow
‘rgba(46, 204, 113, 1)’, // green
‘rgba(52, 152, 219, 1)’, // blue
‘rgba(155, 89, 182, 1)’ // purple
];
return colors[getRandomInt(0, colors.length)];
};
// Particle//粒子模块
var
Particle = function () {
function Particle(system, x, y) {_classCallCheck(this, Particle);
this.system = system;
this.universe = this.system.world.universe;
this.x = x;
this.y = y;
this.color = getRandomColor();
this.life = 1;
this.aging = getRandom(0.990, 0.999); // 0.99, 0.999 || 0.999, 0.9999
this.r = getRandomInt(12, 16);//初始粒子半径范围
this.speed = getRandom(18, 18.5);//粒子爆炸速度范围
this.velocity = [
getRandom(-this.speed, this.speed),
getRandom(-this.speed, this.speed)];
}_createClass(Particle, [{ key: ‘update’, value: function update(
dt) {
this.life *= this.aging;
if (
this.r < 0.1 ||
this.life === 0 ||
this.x + this.r < 0 ||
this.x - this.r > this.universe.width ||
this.y + this.r < 0 ||
this.y - this.r > this.universe.height)
{
this.system.removeObject(this);
}
this.r *= this.life;
this.x += this.velocity[0];
this.y += this.velocity[1];
} }, { key: ‘render’, value: function render(
ctx) {
// Main circle //亮圈模块
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r*1.2, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
var r = this.color.match(/([0-9]+)/g)[0];
var g = this.color.match(/([0-9]+)/g)[1];
var b = this.color.match(/([0-9]+)/g)[2];
// Gradient//梯度变化曲线
var spread = 1.5;
var gradient = ctx.createRadialGradient(
this.x, this.y, this.r,
this.x, this.y, this.r * spread);
gradient.addColorStop(0, ‘rgba(‘ + r + ‘, ‘ + g + ‘, ‘ + b + ‘, 0.5)’);
gradient.addColorStop(1, ‘rgba(‘ + r + ‘, ‘ + g + ‘, ‘ + b + ‘, 0)’);
ctx.globalCompositeOperation = ‘lighter’;
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r * spread, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
ctx.globalCompositeOperation = ‘source-over’;
// Aberration//偏差
var offset = this.r * 0.5;
var color = ‘rgba(‘ + g + ‘, ‘ + b + ‘, ‘ + r + ‘, 0.5)’;
ctx.globalCompositeOperation = ‘lighter’;
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(this.x + offset, this.y + offset, this.r, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
ctx.globalCompositeOperation = ‘source-over’;
} }]);return Particle;}();
// Crown //水波纹圈模块
var
Crown = function () {
function Crown(system, x, y) {_classCallCheck(this, Crown);
this.system = system;
this.x = x;
this.y = y;
this.r = getRandomInt(5, 15); // 5, 20 水波纹圈半径范围
this.mod = 1.1;
this.life = 0.5; //水波纹线
this.aging = getRandom(0.830, 0.899);
this.speed = getRandom(8, 9);
this.color = {
r: getRandomInt(236, 242),
g: getRandomInt(70, 80),
b: getRandomInt(50, 70) };
this.angle1 = Math.PI * getRandom(0, 2);
this.angle2 = this.angle1 + Math.PI * getRandom(0.3, 0.4);//水波纹圈完整度
}_createClass(Crown, [{ key: ‘update’, value: function update(
dt) {
this.life *= this.aging;
if (this.life <= 0.0001) this.system.removeObject(this);
this.r += Math.abs(1 - this.life) * this.speed;
this.x1 = this.x + this.r * Math.cos(this.angle1);
this.y1 = this.y + this.r * Math.sin(this.angle1);
this.angle3 = this.angle1 + (this.angle2 - this.angle1) / 2;
this.x2 = this.x + this.r * this.mod * Math.cos(this.angle3);
this.y2 = this.y + this.r * this.mod * Math.sin(this.angle3);
} }, { key: ‘render’, value: function render(
ctx) {
var gradient = ctx.createRadialGradient(
this.x, this.y, this.r * 0.9,
this.x, this.y, this.r);
gradient.addColorStop(0, ‘rgba(‘ + this.color.r + ‘, ‘ + this.color.g + ‘, ‘ + this.color.b + ‘, ‘ + this.life + ‘)’);
gradient.addColorStop(1, ‘rgba(‘ + this.color.r + ‘, ‘ + this.color.g + ‘, ‘ + this.color.b + ‘, ‘ + this.life * 0.5 + ‘)’);
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, this.angle1, this.angle2, false);
ctx.quadraticCurveTo(this.x2, this.y2, this.x1, this.y1);
ctx.fill();
ctx.closePath();
} }]);return Crown;}();
// Explosion //爆炸模块
var
Explosion = function () {
function Explosion(world, x, y) {_classCallCheck(this, Explosion);
this.world = world;
this.x = x;
this.y = y;
this.objects = [];
var particles = getRandomInt(10, 30); // 10, 30 amount of particles//爆炸 粒子数量
var crowns = particles * getRandom(0.4, 0.5);
while (crowns– > 0) {this.addCrown();}
while (particles– > 0) {this.addParticle();}
}_createClass(Explosion, [{ key: ‘update’, value: function update(
dt) {
this.objects.forEach(function (obj) {
if (obj) obj.update(dt);
});
if (this.objects.length <= 0) {
this.world.clearExplosion(this);
}
} }, { key: ‘render’, value: function render(
ctx) {
this.objects.forEach(function (obj) {
if (obj) obj.render(ctx);
});
} }, { key: ‘addCrown’, value: function addCrown()
{
this.objects.push(new Crown(this, this.x, this.y));
} }, { key: ‘addParticle’, value: function addParticle()
{
this.objects.push(new Particle(this, this.x, this.y));
} }, { key: ‘removeObject’, value: function removeObject(
obj) {
var index = this.objects.indexOf(obj);
if (index !== -1) {
this.objects.splice(index, 1);
}
} }]);return Explosion;}();
// World
var
ConfettiWorld = function () {function ConfettiWorld()
{_classCallCheck(this, ConfettiWorld);}_createClass(ConfettiWorld, [{ key: ‘init’, value: function init()
{
this.objects = [];
window.addEventListener(‘click’, this.explode.bind(this));
// Initial explosion //初始爆炸
var counter = 0;
while (counter– > 0) {
this.explode({
clientX: window.event.clientX, //getRandomInt(10, this.universe.width) , //this.universe.width / 2,
clientY: window.event.clientY //getRandomInt(10, 50) //this.universe.height / 2
});
}
} }, { key: ‘update’, value: function update(
dt) {
this.objects.forEach(function (obj) {
if (obj) obj.update(dt);
});
var amount = this.objects.reduce(function (sum, explosion) {
return sum += explosion.objects.length;
}, 0);
} }, { key: ‘render’, value: function render(
ctx) {
this.objects.forEach(function (obj) {
if (obj) obj.render(ctx);
});
} }, { key: ‘explode’, value: function explode(
event) {
var x = event.clientX;
var y = event.clientY;
this.objects.push(new Explosion(this, x, y));
} }, { key: ‘clearExplosion’, value: function clearExplosion(
explosion) {
var index = this.objects.indexOf(explosion);
if (index !== -1) {
this.objects.splice(index, 1);
}
} }]);return ConfettiWorld;}();
// Time
var
Time = function () {
function Time() {_classCallCheck(this, Time);
this.now = 0; // current tick time
this.prev = 0; // prev tick time
this.elapsed = 0; // elapsed time from last tick
this.delta = 0; // time from last update
this.fps = 60; // desired fps
this.step = 1 / 60; // step duration
}_createClass(Time, [{ key: ‘update’, value: function update(
time) {
this.now = time;
this.elapsed = (this.now - this.prev) / 1000;
this.prev = this.now;
this.delta += this.elapsed;
} }, { key: ‘raf’, value: function raf(
func) {
window.requestAnimationFrame(func);
} }, { key: ‘hasFrames’, value: function hasFrames()
{
return this.delta >= this.step;
} }, { key: ‘processFrame’, value: function processFrame()
{
this.delta -= this.step;
} }]);return Time;}();
// Canvas
var
Universe = function () {
function Universe(element) {_classCallCheck(this, Universe);
this.el = element;
this.ctx = this.el.getContext(‘2d’);
this.pixelRatio = window.devicePixelRatio;
this.time = new Time();
this.worlds = {};
this.world = null; // current state
this.updateSize();
window.addEventListener(‘resize’, this.updateSize.bind(this));
this.addWorld(‘confetti’, ConfettiWorld);
this.setWorld(‘confetti’);
this.start();
}_createClass(Universe, [{ key: ‘start’, value: function start()
{
this.time.raf(this.tick.bind(this));
} }, { key: ‘tick’, value: function tick(
time) {
this.time.update(time);
if (this.time.hasFrames()) {
this.update();
this.time.processFrame();
}
this.render();
this.time.raf(this.tick.bind(this));
} }, { key: ‘update’, value: function update()
{
this.world.update(this.time.step);
} }, { key: ‘render’, value: function render()
{
var gradient = this.ctx.createLinearGradient(0, 0, this.width, this.height);
this.ctx.clearRect(0, 0, this.width, this.height);
this.world.render(this.ctx);
}
<span class="token comment" spellcheck="true">// Helpers 库</span>
}, { key: ‘updateSize’, value: function updateSize()
{
this.width = window.innerWidth;
this.height = window.innerHeight;
this.el.width = this.width * this.pixelRatio;
this.el.height = this.height * this.pixelRatio;
this.el.style.width = window.innerWidth + ‘px’;
this.el.style.height = window.innerHeight + ‘px’;
this.ctx.scale(this.pixelRatio, this.pixelRatio);
} }, { key: ‘addWorld’, value: function addWorld(
worldName, World) {
this.worlds[worldName] = new World();
this.worlds[worldName].universe = this;
this.worlds[worldName].init();
} }, { key: ‘setWorld’, value: function setWorld(
worldName) {
this.world = this.worlds[worldName];
} }]);return Universe;}();
// Main
console.clear();
var element = document.querySelector(‘#canvas1’);
window.Canvas= new Universe(element);
</script>
]]> 时间限制: 1 s|空间限制: 32000 KB
题目描述 Description
汉诺塔问题(又称为河内塔问题),是一个大家熟知的问题。在A,B,C三根柱子上,
有n个不同大小的圆盘(假设半径分别为1-n吧),一开始他们都叠在我A上(如图所示),
你的目标是在最少的合法移动步数内将所有盘子从A塔移动到C塔。
游戏中的每一步规则如下:
\1. 每一步只允许移动一个盘子(从一根柱子最上方到另一个柱子的最上方)
\2. 移动的过程中,你必须保证大的盘子不能在小的盘子上方
(小的可以放在大的上面,最大盘子下面不能有任何其他大小的盘子)
如对于n=3的情况,一个合法的移动序列式:
1 from A to C
2 from A to B
1 from C to B
3 from A to C
1 from B to A
2 from B to C
1 from A to C
给出一个数n,求出最少步数的移动序列
输入描述 Input Description
一个整数n
输出描述 Output Description
第一行一个整数k,代表是最少的移动步数。
接下来k行,每行一句话,N from X to Y,表示把N号盘从X柱移动到Y柱。X,Y属于{A,B,C}
样例输入 Sample Input
3
样例输出 Sample Output
7
1 from A to C
2 from A to B
1 from C to B
3 from A to C
1 from B to A
2 from B to C
1 from A to C
数据范围及提示 Data Size & Hint
n<=10
递归思路分析:
我们设定三个柱子A,B,C。我们的目的是将环从A–>C。(A为起始位置,C为目标位置)
当N=1即一阶时它的路径很简单只需要从A->C进行移动。
当N=2时我们需要进行三步:
1.小盘 A->B
(假想没有大盘只有小盘,与N=1 的步骤一样,只是目标位置变为了 B)
2.大盘 A->C
(大盘上面的小盘到B去了,与N=1 的步骤一样直接到C )
3.小盘 B->C
(大盘到了C,对于小盘而言,C可以看作无盘,与N=1 的步骤一样,只是起始位置变为 B )
(分解一下,小盘从A通过B作为中间目标再到C。可以这样想
小盘下面的大盘目标是C 所以小盘第一次目标则变成B,
等到大盘到了目标C ,小盘再到C。
则完成将大小盘按小盘在上大盘在下的要求移到C。)
当N=3时我们需要进行七步:
1. 小盘 A->C 2.中盘 A->B 3.小盘 C->B
(假想没有大盘只有小盘和中盘,与N=2 的步骤一样,只是目标位置变为了 B)
4. 大盘 A->C,
(大盘上面的小盘和中盘都到B去了,与N=1 的步骤一样直接到C )
5. 小盘 B->A 6.中盘 B->C 7.小盘 A->C
(大盘到了C,对于小盘和中盘而言,C可以看作无盘,与N=2 的步骤一样,只是起始位置变为了 B )
(分解一下,大盘想从A去C。但上面压着小盘与中盘 ,
所以得先把他们移开 并且上面两盘不能移动到C,得移动到B 去
就相当于N=2时,起始位置A到目标位置B。待大盘移动到C。
当前在B 的小盘和中盘,完全就是执行N=2 的步骤。从当前起始位置B 到目标位置C.)
如此执行,通过递归方式。代码思路如下:
1. 对于执行最大盘(n) 到C的操作之前,肯定是?把次大盘(n-1)从A移动到 B 2. 执行最大盘(n) 到C的操作 3.对于执行最大盘(n) 到C的操作之后,肯定是?把次大盘(n-1)从B移动到C
每次只关心上一层,上上层是到了上一层才考虑的事——递归
题目链接:http://codevs.cn/problem/3145/
#include <stdio.h>void han(int n, char A, char B, char C){ if(n == 1)printf("%d from %c to %c\n", n, A, C); else{ //第一步 对于执行最大盘(n) 到C的操作之前 han(n-1, A, C, B); //第二步 执行最大盘(n) 到C的操作 printf("%d from %c to %c\n", n, A, C); //第三步 对于执行最大盘(n) 到C的操作之后 han(n-1, B, A, C); }}int main(){ int n; scanf("%d", &n); printf("%d\n", (1 << n) - 1); han(n, 'A', 'B', 'C'); return 0;}
非递归 思路:
我们先找找规律:
当3个盘的时候:
1 | 1:A–>C |
---|---|
2 | 2:A–>B |
3 | 1:C–>B |
4 | 3:A–>C |
5 | 1:B–>A |
6 | 2:B–>C |
7 | 1:A–>C |
4个的时候:
1 | 1:A–>B |
---|---|
2 | 2:A–>C |
3 | 1:B–>C |
4 | 3:A–>B |
5 | 1:C–>A |
6 | 2:C–>B |
7 | 1:A–>B |
8 | 4:A–>C |
9 | 1:B–>C |
10 | 2:B–>A |
11 | 1:C–>A |
12 | 3:B–>C |
13 | 1:A–>B |
14 | 2:A–>C |
15 | 1:B–>C |
仔细研究研究就能发现,1号出现在·1,3,5,7,9步
2号出现在2,6,10,14 步
3号出现在4,12 步
4号在8,步
规律与2^n有关。
我们在研究研究,三个时:
一号盘的行动方式是:
A–>C
C–>B
B–>A
A–>C
二号盘的行动方式是:
A–>B
B–>C
三号盘的行动方式是:
A–>C
四个时:
一号盘的行动方式是:
A-->B
B–>C
C–>A
A-->B
B–>C
C–>A
A-->B
B–>C
(成一定的周期T=3,当l号盘同最大盘n奇偶性相同,则 执行周期为顺时针,A–>B,B–>C,C–>A
否者则 执行周期为逆时针,A–>C,C–>B,B–>A )
二号盘的行动方式是:
A–>C
C–>B
B–>A
A–>C
三号盘的行动方式是:
A–>B
B–>C
四号盘的行动方式是:
A–>C
总结下:
A号柱有n 个盘子,叫做源柱.移往C 号柱,叫做目的柱.B 号柱叫做中间柱.
全部移往C 号柱要f(n) =(2^n)- 1 次.
最大盘n 号盘在整个移动过程中只移动一次,n-1 号移动2 次,i 号盘移动
2^(n-i)次.
1 号盘移动次数最多,每2 次移动一次.
第2k+1 次移动的是1 号盘,且是第k+1 次移动1 号盘.
第4k+2 次移动的是2 号盘,且是第k+1 次移动2 号盘.
第(2^s)k+2^(s-1)次移动的是s 号盘,这时s 号盘已被移动了k+1 次.
每2^s 次就有一次是移动s 号盘.
第一次移动s 号盘是在第2^(s-1)次.
第二次移动s 号盘是在第2^s+2^(s-1)次.
第k+1 次移动s 号盘是在第k*2^s+2^(s-1)次.
A–>B,B–>C,C–>A叫做顺时针方向,A–>C,C–>B,B–>A叫做逆时针方向.
最大盘n 号盘只移动一次:A–>C它是逆时针移动.
n-1 移动2 次:A–>B,B–>C,是顺时针移动.
代码实现:
枚举 1, 2, 3, 4·····i, i+1, i+2, ·····步。
先 获取 第i步移动的几号盘,根据 (2^s)k+2^(s-1)=i,转化一下,满足 i%(2^s) =2^(s-1) ,令t=2^s;则有i%t=t/2
再 获得第S盘 第几次移动 ,根据 (2^s)k+2^(s-1)=i, k=i/(2^s) ,即 k=i/t;
最后 根据周期T 与奇偶性 确定具体移动的步骤(共6六种)
代码:
#include<stdio.h>int main(){long long i, res,t,k;int n,s;scanf("%d", &n);res=(1<<n)-1; printf("%lld\n",res); for( i=1; i <=res; i++ ){ for( t=2,s=1; s<= n; s++,t*=2)if( i%t == t/2 ) break;//i%t=t/2 找 第i步移动的S号盘 k = i/t;//获得第S盘 第几次移动 if( n%2 == s%2 ){// 逆时针 if( (k+1)%3 == 0 ) printf("%d from B to A\n",s); if( (k+1)%3 == 1 ) printf("%d from A to C\n",s); if( (k+1)%3 == 2 ) printf("%d from C to B\n",s); } else{// 逆时针 if( (k+1)%3 == 0 ) printf("%d from C to A\n",s); if( (k+1)%3 == 1 ) printf("%d from A to B\n",s); if( (k+1)%3 == 2 ) printf("%d from B to C\n",s); } } return 0;}
更多详情请到:Five-菜鸟级
]]>K-进制数
题目描述
考虑包含N位数字的K-进制数. 定义一个数有效, 如果其K-进制表示不包含两连续的0.
考虑包含N位数字的K-进制数. 定义一个数有效, 如果其K-进制表示不包含两连续的0.
例:
1010230 是有效的7位数
1000198 无效
0001235 不是7位数, 而是4位数.
给定两个数N和K, 要求计算包含N位数字的有效K-进制数的总数.
假设2 <= K <= 10; 2 <= N; 4 <= N+K <= 18.输入
两个十进制整数N和K
2
10
输出
十进制表示的结果
90
样例输入
样例输出
根据题意,要知道 N 位K 进制并且 不能有连续两个0出现 还有首位不能为0 的限制条件。
本着由简到难的思想 :
假设是让你求 1位 K 进制的满足条件的数,那么满足条件的数则有 1,2,3…..K-1 一共K-1个数对吧,
我们记作 res_1=K-1,那么不满足条件的数 只有 0 ,一共1个数 ,我们记作res_0=1。
假设是让你求 2位 K 进制的满足条件的数,那么先考虑首位(也就是第2位),可以填的数为除去0的其他数,
有 1,2,3…..K-1 一共K-1个数对吧,而这第二位可以填的数 可以和第一位的所有数搭配,
以1为例,有 11,12,13,…..1(K-1),还有在第一位不满足条件的 0 搭配 10,也是满足条件的数,
所以2位K进制满足条件的数res_1=(K-1)(K-1+1),即 res_1=(K-1)(res_1+res_0),对吧,
再来看不满足条件的数 即 首位为0的 有 01,02,03…..0(K-1),一共有K-1个也就是res_0=K-1,即 res_0=res_1(上一个)。
第一位满足条件的数res_1对吧,因为不能连0 ,虽然00也是不满足,但是 00这种情况是绝对不满足,
而首位不满足的情况是相对不满足,绝对和相对 懂吧。
那么继续,假设是让你求 3位 K 进制的满足条件的数,同样先考虑首位(也就是第3位),
可以填的数为除去0的其他数,有 1,2,3…..K-1 一共K-1个数对吧,而这第3位可以填的数
可以和2位K进制满足条件和(相对)不满足条件的数搭配,即 res_1=(K-1)[(K-1)(K-1+1)+(K-1)],
即 res_1=(K-1)(res_1+res_0),不满足条件的数则是可以和2位K进制满足条件的数搭配,
res_0=(k-1)(K-1+1),即res_0=res_1。
后面的位数就以此类推,再看看图解。
AC代码:
#include<stdio.h>int main(){ int N,K,i,res_0,res_1;//res_1代表最高位非0 res_0代表最高位为0的结果 while(scanf("%d%d",&N,&K)!=EOF){ res_1=K-1,res_0=1;//如果只有一位时 K进制首位为1的可以填的为K-1个数去掉为0 for(i=2;i<=N;i++){ int last_res_1=res_1;//暂存 res_1=(K-1)*(res_1+res_0);//如果高位为1 则结果为上一次结果为1和为0的数的个数 res_0=last_res_1; //如果高位为0 则结果为上一次结果为1的数的个数 } printf("%d\n",res_1); } return 0;}
]]>
题目描述
牛牛喜欢整数序列,他认为一个序列美丽的定义是
1:每个数都在0到40之间
2:每个数都小于等于之前的数的平均值
具体地说:for each i, 1 <= i < N, A[i] <= (A[0] + A[1] + … + A[i-1]) / i.
3:没有三个连续的递减的数
现在给你一个序列,每个元素是-1到40,你可以将序列中的-1修改成任意的数,求你可以得到多少个美丽序列,答案对1e9+7取模
输入描述:
第一行输入一个整数n (1 ≤ n ≤ 40)
第二行输入n个整数
输出描述:
输出一个整数
示例1
输入
23 -1
输出
4
示例2
输入
3
5 3 -1
输出
2
示例3
输入
3-1 0 40
输出
0
示例4
输入
11-1 40 -1 -1 -1 10 -1 -1 -1 21 -1
输出
579347890
备注:
子任务1: n <= 10子任务2: n <= 20子任务3: 无限制
题目链接:https://ac.nowcoder.com/acm/problem/21313
解题思路:
按照动态规划的一般步骤 , 假如 有个序列 * 5 我们需要知道 当前数与前一个数的大小关系
AC代码:
#include<string.h>#include<iostream>#define Mod 1000000007using namespace std; int main(){ int n; long long a[42]; long long dp[42][42][3][1602]; // dp[i][j][1][k]代表当前 处理到第i个且值为j 在递减序列中第 1个前i个和为k memset(dp,0,sizeof(dp)); cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; //初始化 if(a[1]==-1) {for(int i=0;i<=40;i++)dp[1][i][1][i]=1;} else dp[1][a[1]][1][a[1]]=1; for(int i=2;i<=n;i++){ if(a[i]==-1){//若当前数为 -1 即可为任何数 for(int j=0;j<=40;j++){//枚举当前可能的数 0~40 for(int L=0;L<=40;L++){ //枚举当前前一个(i-1)可能的数 0~40 for(int k=j*(i-1);k<=1600-j;k++){//枚举前(i-1)个满足条件的和k if(j>=L){//若当前大于前一个数 即打破递减序列的条件 dp[i][j][1][k+j]=(dp[i][j][1][k+j]+dp[i-1][L][1][k])%Mod; dp[i][j][1][k+j]=(dp[i][j][1][k+j]+dp[i-1][L][2][k])%Mod; }else dp[i][j][2][k+j]=(dp[i][j][2][k+j]+dp[i-1][L][1][k])%Mod; } } } }else{//若为具体的大小 for(int L=0;L<=40;L++){//枚举上一个数的大小 for(int k=a[i]*(i-1);k<=1600-a[i];k++){//枚举前(i-1)个满足条件的和k if(a[i]>=L){ dp[i][a[i]][1][k+a[i]]=(dp[i][a[i]][1][k+a[i]]+dp[i-1][L][1][k])%Mod; dp[i][a[i]][1][k+a[i]]=(dp[i][a[i]][1][k+a[i]]+dp[i-1][L][2][k])%Mod; }else dp[i][a[i]][2][k+a[i]]=(dp[i][a[i]][2][k+a[i]]+dp[i-1][L][1][k])%Mod; } } } } long long sum=0; for(int j=0;j<=40;j++){//枚举 可能的大小 for(int k=j*n;k<=1600;k++){//枚举可能的和 sum=(sum+dp[n][j][1][k])%Mod; //当前数大小为j且在递减位置1 和为k的美丽序列数 sum=(sum+dp[n][j][2][k])%Mod; } } cout <<sum<<endl; return 0;}
题目描述
牛牛喜欢回文串,牛妹给了牛牛一个字符串S,牛牛想把S变成回文串
牛牛可以做如下三种操作
1:在任意位置增加一个字符
2:删除一个字符
3:改变一个字符
每种操作都有限定的字符,比如,只能删除’a’,增加’b’,把’c’变成’d’等等
每种操作都有相应的代价
用M条语句来描述能进行的操作
add c x 表示增加c字符需要x的代价
erase c x表示删除c字符需要x的代价
change c1 c2 x表示将c1 改成c2需要x的代价
求牛牛想要得到回文串需要的最少代价
如果不行输出-1输入描述:
第一行输入一个字符串S(都是小写字母)表示牛妹给牛牛的串(1 ≤ |S| ≤ 50)
第二行输入一个整数m (0 ≤ m ≤ 50)
接下来m行的格式是
add c x
erase c x
change c1 c2 x
三种中的一种
c c1 c2都是小写字母
1 ≤ x ≤ 100000
所有允许的操作去除x部分后都是不同的输出描述:
输出一个整数示例1
输入
racecar
0输出
0示例2
输入
caaaaaab
change b a 100000
change c a 100000
change c d 50000
change b e 50000
erase d 50000
erase e 49999输出
199999示例3
输入
moon
erase o 5
add u 7
change d p 3
change m s 12
change n d 6
change s l 1输出
-1示例4
输入
xab
change a c 1
change b d 1
change c e 1
change d e 1
add y 1
change y z 1
change x z 1输出
7
AC代码:
#include<stdio.h>#include<iostream>#include<string.h>#define INF 1e14 #define LL long longusing namespace std;char str[55];LL dp[55][55],cost_add[30],cost[30],cost_err[30],C[30][30];//变换表 //dp[i][j]代表i~j段对称的最小花费 void init(){//初始化 for(int i=0;i<=26;i++){ cost[i]=cost_add[i]=cost_err[i]=INF; for(int j=0;j<=26;j++) C[i][j]=INF; } }void Floyd(){ for(int k=0;k<26;k++) for(int i=0;i<26;i++) for(int j=0;j<26;j++) C[i][j]=min(C[i][j],C[i][k]+C[k][j]);//建立变换表 for(int i=0;i<26;i++) for(int j=0;j<26;j++) { cost[i]=min(cost[i],min(cost_add[i],cost_err[i]));//直接通过增加或则删除该字母 cost[i]=min(cost[i],C[i][j]+min(cost_err[j],cost_add[j]));//间接接通过先变换再增加或则删除该字母 cost[i]=min(cost[i],cost_add[j]+C[j][i]);//增加该字母再改变到需要的字母 for(int k=0;k<26;k++) cost[i]=min(cost[i],C[i][j]+cost_add[k]+C[k][j]);//一边增加 一边变换中间字母 }}int main(){ scanf("%s",str+1); int m,x; char in[10]; char a,b; scanf("%d",&m); init(); for(int i=0;i<m;i++){ scanf("%s",in);getchar(); if(in[0]=='a')scanf("%c %d",&a,&x),cost_add[a-'a']=min(cost_add[a-'a'],(LL)x); if(in[0]=='e')scanf("%c %d",&a,&x),cost_err[a-'a']=min(cost_err[a-'a'],(LL)x); if(in[0]=='c')scanf("%c %c %d",&a,&b,&x),C[a-'a'][b-'a']=min(C[a-'a'][b-'a'],(LL)x);<span class="token punctuation">}</span><span class="token function">Floyd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//弗洛伊德建立花费表 </span><span class="token keyword">int</span> len<span class="token operator">=</span><span class="token function">strlen</span><span class="token punctuation">(</span>str<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token operator">=</span>len<span class="token punctuation">;</span>i<span class="token operator">>=</span><span class="token number">1</span><span class="token punctuation">;</span>i<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> j<span class="token operator">=</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">;</span>j<span class="token operator"><=</span>len<span class="token punctuation">;</span>j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">=</span>INF<span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>str<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">==</span>str<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">)</span> dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">=</span>dp<span class="token punctuation">[</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token number">-1</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//相同则不花费 </span> dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">=</span><span class="token function">min</span><span class="token punctuation">(</span>dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">,</span>dp<span class="token punctuation">[</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">+</span>cost<span class="token punctuation">[</span>str<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-</span><span class="token string">'a'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//处理左边 </span> dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">=</span><span class="token function">min</span><span class="token punctuation">(</span>dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">,</span>dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token number">-1</span><span class="token punctuation">]</span><span class="token operator">+</span>cost<span class="token punctuation">[</span>str<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">-</span><span class="token string">'a'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//处理右边 </span> dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">=</span><span class="token function">min</span><span class="token punctuation">(</span>dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">,</span>dp<span class="token punctuation">[</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token number">-1</span><span class="token punctuation">]</span><span class="token operator">+</span><span class="token function">min</span><span class="token punctuation">(</span>C<span class="token punctuation">[</span>str<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">-</span><span class="token string">'a'</span><span class="token punctuation">]</span><span class="token punctuation">[</span>str<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-</span><span class="token string">'a'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>C<span class="token punctuation">[</span>str<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-</span><span class="token string">'a'</span><span class="token punctuation">]</span><span class="token punctuation">[</span>str<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">-</span><span class="token string">'a'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//两边同时变换中字母 </span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> k<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span>k<span class="token operator"><=</span><span class="token number">26</span><span class="token punctuation">;</span>k<span class="token operator">++</span><span class="token punctuation">)</span> dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">=</span><span class="token function">min</span><span class="token punctuation">(</span>dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">,</span>dp<span class="token punctuation">[</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token number">-1</span><span class="token punctuation">]</span><span class="token operator">+</span>C<span class="token punctuation">[</span>str<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">-</span><span class="token string">'a'</span><span class="token punctuation">]</span><span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token operator">+</span>C<span class="token punctuation">[</span>str<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">-</span><span class="token string">'a'</span><span class="token punctuation">]</span><span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">if</span><span class="token punctuation">(</span>dp<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span>len<span class="token punctuation">]</span><span class="token operator">==</span>INF<span class="token punctuation">)</span> cout<span class="token operator"><<</span><span class="token string">"-1"</span><span class="token operator"><<</span>endl<span class="token punctuation">;</span><span class="token keyword">else</span> cout<span class="token operator"><<</span>dp<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span>len<span class="token punctuation">]</span><span class="token operator"><<</span>endl<span class="token punctuation">;</span><span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
爱丽丝有一只猴子,她必须每天给猴子喂水果。她有三种水果,香蕉,桃子和苹果。每天,她都会选择三分之一,
然后选择其中一种喂猴子。但是猴子是很挑剔的,它不希望香蕉连续吃超过D1天,桃子连续超过吃D2天,或苹果连续吃D3天以上。现在爱丽丝有N1香蕉,N2桃子和N3。苹果,请帮她计算一下喂猴子的计划。
现在爱丽丝有N1香蕉,N2桃子和N3。苹果,请帮她计算一下喂猴子的计划。
输入
多个测试用例。第一行包含一个整数T (T<=20),表示测试用例的数量。
每个测试用例是一个包含6个整数N1、N2、N3、D1、D2、D3 (N1、N2、N3、D1、D2、D3<=50)。
输出
输出一行。在(N1+N2+N3)天内喂养猴子的计划数目。答案太大了,所以你应该对1000000007取模。
样例输入
1
2 1 1 1 1 1
样例输出
6
#include<stdio.h>#include<string.h>#define N 51#define MOD 1000000007#define min(a,b) a>b?b:atypedef long long ll;int main(){ int T,n1,n2,n3,x1,x2,x3; long int dp[N][N][N][4]; int tem,i,j,k,s; scanf("%d",&T); while(T--) { ll ans=0; memset(dp,0,sizeof(dp)); scanf("%d%d%d%d%d%d",&n1,&n2,&n3,&x1,&x2,&x3); for(i=n1;i>=0;i--) for(j=n2;j>=0;j--) for(k=n3;k>=0;k--) { tem=min(i,x1); for(s=1;s<=tem;s++) if(i==n1&&j==n2&&k==n3)dp[i-s][j][k][1]=(dp[i][j][k][1]+1)%MOD; else dp[i-s][j][k][1]=(dp[i-s][j][k][1]+(dp[i][j][k][2]+dp[i][j][k][3])%MOD)%MOD; tem=min(j,x2); for(s=1;s<=tem;s++) if(i==n1&&j==n2&&k==n3)dp[i][j-s][k][2]=(dp[i][j][k][2]+1)%MOD; else dp[i][j-s][k][2]=(dp[i][j-s][k][2]+(dp[i][j][k][1]+dp[i][j][k][3])%MOD)%MOD; tem=min(k,x3); for(s=1;s<=tem;s++) if(i==n1&&j==n2&&k==n3)dp[i][j][k-s][3]=(dp[i][j][k][3]+1)%MOD; else dp[i][j][k-s][3]=(dp[i][j][k-s][3]+(dp[i][j][k][1]+dp[i][j][k][2])%MOD)%MOD; } ans=(dp[0][0][0][1]+dp[0][0][0][2]+dp[0][0][0][3])%MOD; printf("%lld\n",ans); } return 0;}
#include<stdio.h>#include<string.h>#define N 51#define MOD 1000000007typedef long long ll;int vis[N][N][N][N][3];int x1,x2,x3,tem;int DFS(int n1,int n2,int n3,int cot,int lost){ if(cot==0||n1<0||n2<0||n3<0)return 0; if(vis[n1][n2][n3][cot][lost]!=-1)return vis[n1][n2][n3][cot][lost]; if(n1+n2+n3==0)return vis[n1][n2][n3][cot][lost]=1; ll ans=0;int t[3]={0};t[lost]=cot; if(t[0]<x1)ans=DFS(n1-1,n2,n3,t[0]+1,0)%MOD; if(t[1]<x2)ans=(ans+DFS(n1,n2-1,n3,t[1]+1,1))%MOD; if(t[2]<x3)ans=(ans+DFS(n1,n2,n3-1,t[2]+1,2))%MOD; return vis[n1][n2][n3][cot][lost]=ans;}int main(){ int T, n1,n2,n3; scanf("%d",&T); while(T--) { ll ans=0; memset(vis,-1,sizeof(vis)); scanf("%d%d%d%d%d%d",&n1,&n2,&n3,&x1,&x2,&x3); ans=DFS(n1-1,n2,n3,1,0)%MOD; ans=(ans+DFS(n1,n2-1,n3,1,1))%MOD; ans=(ans+DFS(n1,n2,n3-1,1,2))%MOD; printf("%lld\n",ans); } return 0;}
]]>时间限制: 1Sec 内存限制: 128MB 提交: 62 解决: 12
题目描述
n个人参加某项特殊考试。
为了公平,要求任何两个认识的人不能分在同一个考场。
求是少需要分几个考场才能满足条件。
输入
第一行,一个整数n(1<n<100),表示参加考试的人数。
第二行,一个整数m,表示接下来有m行数据
以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识。
输出
一行一个整数,表示最少分几个考场。
样例输入
5
8
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
样例输出
4思路:可以抽象为无向图染色问题。相邻顶点不能染相同颜色,问至少要用多少种颜色。
用DFS搜搜搜。
假设 n 个人需要 kcs 个考场 ,先在 kcs 个考场 安排n 个人 如果安排不下 再增加考场数。
通过DFS +剪枝 从所有可能情况中得到最小考场数。
#include<stdio.h>#include<string.h>#define N 301#define min(a,b) a>b?b:a int gxb[N][N];//关系表 int p[N][N];// 房间状态 int num=N,n;void DFS(int x,int kcs)//x 代表当前安排了多少个人 kcs 代表考场数{ if(kcs>=num)return;//剪子 if(x==n+1){num=min(num,kcs);return;}//如果已经安排了n个人,进行判断 int j,k; for(j=1;j<=kcs;j++)//枚举考场 { k=0; while(p[j][k]&&!gxb[x][p[j][k]])k++;//找到一个空位 并且与该考场人无关系 if(p[j][k]==0)p[j][k]=x,DFS(x+1,kcs),p[j][k]=0;//满足条件 进行下一考生 } //回溯 p[j][0]=x; DFS(x+1,kcs+1);// 如果所有房间都不满足条件 增加房间 p[j][0]=0;//回溯 }int main(){ int m,i,s1,s2; memset(gxb,0,sizeof(gxb)); memset(p,0,sizeof(p)); scanf("%d\n%d",&n,&m); for(i=1;i<=m;i++) { scanf("%d%d",&s1,&s2); gxb[s1][s2]=gxb[s2][s1]=1;//建关系 } DFS(1,1); printf("%d\n",num); return 0;}
http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/3562.html
1640: 题目 B Proxy
时间限制: 1 Sec 内存限制: 128 MB
提交: 5 解决: 2
[提交][状态][讨论版] [Edit] [TestData]
题目描述
由于GFW (Great Firewall),我们不能直接访问很多网站,如Facebook、Twitter、YouTube等,
但在代理服务器和代理服务器的帮助下,我们可以很容易地访问这些网站。
您有多个代理服务器的列表,其中一些可以直接连接,而另一些则不能。
但是您可以通过其他代理服务器通过单向连接访问代理服务器。我们都知道,网络访问的滞后将决定我们对访问的感受。
你有一个非常智能的代理软件,一旦你选择了一个可直接访问的代理服务器,你就会发现你可以找到最慢的方法到达网站。
你知道每一个联系的滞后。你访问的滞后是你整个联系的全部滞后。您希望最小化访问延迟,您将选择哪个代理服务器?
输入
输入多个测试用例,
第一行是整数T (T <= 100),表示测试用例的数量。
每个测试用例的第一行是两个整数N (0 <= N <= 1000), M (0 <= M <= 20000)。
N是代理服务器的数量(从1到N)。0是你的电脑的标签,(N+1)是目标网站服务器的标签。
然后M行,每一行包含三个u, v, w (0 <= u, v <= N + 1, 1 <= w <= 1000),表示u可以直接连接到v,滞后是w。
输出
对于每个测试用例,您将选择直接连接的代理服务器的一个整数。您只能选择直接从您的计算机连接的代理服务器。
如果有多个选择,您应该用最少的标签输出代理服务器。如果你不能以任何方式访问目标网站,输出“-1”(没有引号)。
如果你可以直接访问目标网站,而且延迟是最小的,输出“0”(没有引号)。
样例输入
4
3 6
0 1 10
1 2 1
2 4 4
0 3 2
3 2 1
3 4 7
2 4
0 2 10
0 1 5
1 2 4
2 1 7
1 3
0 2 1
0 1 2
1 2 1
1 3
0 2 10
0 1 2
1 2 1
样例输出
3
-1
0
1
思路:迪杰斯特拉 反向建树
#include<stdio.h>#include<string.h>#define N 1002#define Min(a,b) a>b?b:a#define INF 1000000int dis[N],bj[N];int mp[N][N];int n;void djsk(int v){ int i,j,k,min; for(i=0;i<=n;i++) dis[i]=mp[v][i];//初始化dis数组 dis[i]=5代表从起始点到i点的最短距离 dis[v]=0;// v 代表起始节点 自己到自己为0 bj[v]=1;// 标记 已找到短路 for(i=0;i<=n;i++)// i 代表已经找到的最短路条数 { min=INF;k=0; for(j=0;j<=n;j++)//从未找到最短路径元素中找一个路径最短的 if(!bj[j]&&dis[j]<min)min=dis[j],k=j; bj[k]=1;// 标记 已找到短路 for(j=0;j<=n+1;j++)//用但前最短路节点更新未找到最短路的节点 if(!bj[j]&&dis[j]>(dis[k]+mp[k][j]))dis[j]=dis[k]+mp[k][j]; }}int main(){ int T,m,i,j,u,v,w,ans; scanf("%d",&T); while(T--) { memset(bj,0,sizeof(bj)); scanf("%d%d",&n,&m); for(i=0;i<=n+1;i++) for(j=0;j<=n+1;j++) mp[i][j]=INF; for(i=0;i<=n+1;i++)mp[i][i]=0; for(i=1;i<=m;i++) {scanf("%d%d%d",&u,&v,&w); mp[v][u]=w; } djsk(n+1); if(dis[0]==INF)printf("-1\n"); else { ans=INF; for(i=1;i<=n+1;i++) if(dis[i]+mp[i][0]==dis[0]&&i<ans)ans=i; if(ans==n+1)printf("0\n"); else printf("%d\n",ans); } }return 0;
}
#include<stdio.h>#include<string.h>#define N 1002#define Min(a,b) a>b?b:a#define INF 1000000int dis[N],s[2][N];int mp[N][N];int n;void djsk(int v){ int i,j,k,min,q=0,d=0,c=0; for(i=0;i<=n;i++) s[c][q++]=i,dis[i]=mp[v][i];//初始化dis数组 dis[i]=5代表从起始点到i点的最短距离 dis[v]=0;// v 代表起始节点 自己到自己为0 while(q)//没有未找到最短路的元素 { min=INF;k=-1; for(j=0;j<q;j++)//从未找到最短路径元素中找一个路径最短的 if(dis[s[c%2][j]]<min) { min=dis[s[c%2][j]]; if(k!=-1)s[(c+1)%2][d++]=k; k=s[c%2][j]; } else s[(c+1)%2][d++]=s[c%2][j]; if(q==d)break;//寻找无改变 则未联通 for(j=0;j<d;j++)//用但前最短路节点更新未找到最短路的节点 if(dis[s[(c+1)%2][j]]>(dis[k]+mp[k][s[(c+1)%2][j]]))dis[s[(c+1)%2][j]]=dis[k]+mp[k][s[(c+1)%2][j]]; c=(c+1)%2;q=d;d=0;//交换层次 }}int main(){ int T,m,i,j,u,v,w,ans; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(i=0;i<=n+1;i++) for(j=0;j<=n+1;j++) mp[i][j]=INF; for(i=0;i<=n+1;i++)mp[i][i]=0; for(i=1;i<=m;i++) {scanf("%d%d%d",&u,&v,&w); mp[v][u]=w; } djsk(n+1); if(dis[0]==INF)printf("-1\n"); else { ans=INF; for(i=1;i<=n+1;i++) if(dis[i]+mp[i][0]==dis[0]&&i<ans)ans=i; if(ans==n+1)printf("0\n"); else printf("%d\n",ans); } }return 0;
}
]]>给定一个长度为n的字符串S,还有一个数字L,统计长度大于等于L的出现次数最多的子串(不同的出现可以相交),
如果有多个,输出最长的,如果仍然有多个,输出第一次出现最早的。
数据规模和约定
n< =60
S中所有字符都是小写英文字母。
提示
枚举所有可能的子串,统计出现次数,找出符合条件的那个
输入
第一行一个数字L。
第二行是字符串S。
L大于0,且不超过S的长度。
输出
一行,题目要求的字符串。
样例输入
4
bbaabbaaaaa
样例输出
bbaa
思路: 枚举 匹配 通过 指针移动
#include<stdio.h>#include<string.h>int main(){ char s[1000],c[100],r[100];int len,n,i,j,ans=0,t,m; //母串 动态字串 结果字串 scanf("%d",&n); scanf("%s",&s); len=strlen(s); for(m=n;m<=len/2||m==n;m++) //大于等于n的可取范围; { char *p=s; i=len-m+1; //初始化 while(i--) {strncpy(c,p++,m); c[m]='\0';//获取动态字串 t=0; char *q=s;j=len-m+1; while(j--){if(strncmp(c,q++,m)==0)t++; }//枚举字串比较 if(t>ans||(t==ans&&m>strlen(r)))ans=t,strcpy(r,c); } }printf("%s\n",r);return 0;}
最长的递增子序列
Bobo学会了如何计算ICPCCamp中O(nlogn)中的最长增加子序列(LIS)。
对于那些没有加入ICPCCamp的人来说,召回LIS(a1,a2,…,an)被定义为f [1] 2⊕f [2] 2⊕???⊕f [n] 2其中⊕表示 异或(XOR)和f计算如下。
因为我在[1,2,…,n]
对于[1,2,…,i-1]中的j,f [i] = 1
如果a [j] <a [i]那么
f [i] = max(f [i],f [j] +1)
给定序列A =(a1,a2,…,an),Bobo希望找到LIS(B1),LIS(B2),…,LIS(Bn),其中Bi是移除第i个 元素来自A.
输入
输入包含零个或多个测试用例,并由文件结束符终止。 对于每个测试用例:
第一行包含一个整数n。 第二行包含n个整数a1,a2,…,an。
?2≤n≤5000
?1≤ai≤n
?测试用例的数量不超过10个。
产量
对于每种情况,输出表示LIS(B1),LIS(B2),…,LIS(Bn)的n个整数。
示例输入
五
2 5 3 1 4
示例输出
5 13 0 8 0
Longest Increasing Subsequence
Bobo learned how to compute Longest Increasing Subsequence (LIS) in O(nlogn) in ICPCCamp.
For those who did not attend ICPCCamp as Bobo, recall LIS(a1,a2,…,an) is defined as f[1]2 ⊕ f[2]2 ⊕ ??? ⊕ f[n]2 where ⊕ denotes the exclusive-or (XOR) and f is calculated as follows.
for i in [1, 2, …, n]
f[i] = 1 for j in [1, 2, …, i - 1]
if a[j] < a[i] then
f[i] = max(f[i], f[j] + 1)
Given sequence A = (a1,a2,…,an), Bobo would like to find LIS(B1),LIS(B2),…,LIS(Bn) where Bi is the sequence after removing the i-th element from A.
Input
The input contains zero or more test cases and is terminated by end-of-file. For each test case:
The first line contains an integer n. The second line contains n integers a1,a2,…,an.
? 2 ≤ n ≤ 5000
? 1 ≤ ai ≤ n
? The number of test cases does not exceed 10.
Output
For each case, output n integers which denote LIS(B1),LIS(B2),…,LIS(Bn).
Sample Input
5
2 5 3 1 4
Sample Output
5 13 0 8 0
思路:动态规划 +最长递增子序列思想 先将 数字序列每个长度的最长的递增子序列长度找到
例如 1 2 3 4 5 (下标)
a[i] 2 5 3 1 4
dp[i] 1 2 2 1 3 dp[i]代表当前序列长度 的最大递增子序列长度 (与导弹拦截一样)
dp[1]=1 ( 2 )
dp[2]=2 (2,5)
dp[3]=2 (2,3)
dp[4]=1 ( 1 )
dp[5]=3 (2,3,4)
#include<stdio.h>#include<string.h>#define max(a,b) a>b?a:b#define min(a,b) a<b?a:b#define N 5002int main(){ int n,i,j;int a[N],dp[N],s[N];long long ans; // s[i] i 代表 递增子序的长度 s[i]存 此长度最小的末元素的值 // 例如 s[2]=3 代表 长度为2 的增序末端值为 3 // 此题 长度2 有(2,5) (2,3)为撒s[2]=5不行 如果后面是 6 那么增序肯定变为3 但如果 4 就会有问题 while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=n;i++) //初始化 没删元素之前的 每个元素构成的子序列长度 { dp[i]=1; //至少本身为 1 for(j=1;j<=i-1;j++) if(a[j]<a[i]) dp[i]=max(dp[i],dp[j]+1); } for(i=1;i<=n;i++)//遍历要移除的序号 { memset(s,10000,sizeof(s)); ans=0; s[0]=0; for(j=1;j<=i-1;j++)//处理 移除序号 之前的 (移除序号值不影响之前的增序长度) s[dp[j]]=min(s[dp[j]],a[j]), ans^=dp[j]*dp[j]; for(j=i+1;j<=n;j++)//处理 移除序号 之后的 { if(a[j]>s[dp[j]-1])// 当前序号处理的值 大于比这个序号的原本长度-1的最小值 s[dp[j]]=min(s[dp[j]],a[j]),ans^=dp[j]*dp[j]; //也就是说 移除元素不影响 else//否则 会影响 因此被影响的增序长度-1 s[dp[j]-1]=min(s[dp[j]-1],a[j]),ans^=(dp[j]-1)*(dp[j]-1);} if(i!=1)printf(" ");printf("%lld",ans); } printf("\n"); } return 0;}
#include <stdio.h>#include<string.h>int next[100];void getnext(char a[100],int n)//next值的获取 { int i=0,j=-1;//初始 next[0]=-1; while(i<n) { if(j==-1||a[i]==a[j]) { j++,i++,next[i]=j; if(a[i]==a[j])next[i]=next[j];//优化部分 优化 优化前缀与后缀 相同 例如 abcabcabc } else j=next[j];//不匹配回溯到上一个匹配点 } }int kmp(char a[100],char b[100],int lea,int leb)//kmp 函数 { getnexth(a,lea);//next值的获取 int i=0,j=0,w=0; while(i<leb) { if(j==-1||a[j]==b[i])i++,j++; else j=next[j]; if(j==lea)break; // if(j==lea)w++,j=next[j]; } if(j==lea)w=i-j+1; return w;}int main(){ int lea,leb; char a[100],b[100]; while(scanf("%s%s",&b,&a)!=EOF)//b 被匹配串 a模板串 { //scanf("%s",&b); //scanf("%s",&a); lea=strlen(a); leb=strlen(b); printf("%d\n",kmp(a,b,lea,leb)); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(next,0,sizeof(next)); }return 0;}
]]>问题描述 小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分,代表他的围棋水平。
小明发现网站的自动对局系统在匹配对手时,只会将积分差恰好是K的两名用户匹配在一起。 如果两人分差小于或大于K,系统都不会将他们匹配。
现在小明知道这个网站总共有N名用户,以及他们的积分分别是A1, A2, … AN。
小明想了解最多可能有多少名用户同时在线寻找对手,但是系统却一场对局都匹配不起来 (任意两名用户积分差不等于K)? 输入格式
第一行包含两个个整数N和K。 第二行包含N个整数A1, A2, … AN。对于30%的数据,1 <= N <= 10 对于100%的数据,1 <= N <= 100000, 0 <= Ai <=
100000, 0 <= K <= 100000 输出格式 一个整数,代表答案。 样例输入 10 0 1 4 2 8 5 7 1 4 2
8 样例输出 6
题目链接:C语言网: http://www.dotcpp.com/oj/problem1842.html
蓝桥杯: http://lx.lanqiao.cn/problem.page?gpid=T454
如果 用户积分之间相互有冲突 要想最多人 则需 每隔k积分的用户在线如下图
假设每个 积分段的用户 都一样的话 则要么取蓝色积分的用户 要么取红色用户都行
但是如果 积分人数如下图 肯定 每隔一个取得办法就不行了 正解 应该是看下面吧
正解:取红色部分
人眼看一眼就知道了 计算机 则需要动态规划的方式来到达目的 下面是该题的核心(理论就不讲了 讲讲具体实现 体会动态更新的过程)
从冲突用户第3个用户开始 那么他只能与他前前用户可以同时在线
所以 dp[6]=dp[2]+5=11 (dp[i]=k 代表 从第1个积分的用户到积分为i的用户 可同时在线的最大人数)
然后 更新一下 他 前面一个积分用户的dp[i-k]的值,为他后面一个积分的用户做准备 dp[i-k]=Max(dp[i-k],dp[i-2*k]);
更新dp[i-k] 这个时候dp[i-k]=dp[4]=2就替换dp[i-2*k]=dp[2]=6 实质就是隔了2k
当处理第4个积分用户的 dp[8] 只需找他前前一个积分用户
然后更新他前一个 积分的用户 但是dp[i-k]>dp[i-2*k] 所以无需更新
。。。。。
更新 到最后一个积分用户 就可以 得出当 积分为 2 4 6 8 10 12 这组相互冲突的用户之间 最大的可同时在线人数了
综上 :
就可以得出
dp[i]=jf[i]+dp[i-2k];//从第1个积分用户到当前积分的最大人数
dp[i-k]=Max(dp[i-k],dp[i-2k]);//更新当前上一个积分用户
当然 也可以优化一下空间复杂度
用 dp替换dp[i] qq_dp替换dp[i-2*k] q_dp替换dp[i-k]
节省掉dp 开的空间
写为
qq_dp=jf[ks]; q_dp=jf[ks+k]; for(i=ks+2*k;i<=js;i=i+k) { dp=jf[i]+qq_dp; //更新从第一到当前最大 积分只要至少隔一个k就行了 所以 本积分人数加上比他小两个k积分的用户人数 q_dp=Max(q_dp,qq_dp);//更新前一个k积分用户 qq_dp=q_dp; q_dp=dp; }
AC代码:
#include <stdio.h>#include <string.h>long int jf[100012]={0};//jf[i]=k 代表积分为i的用户 有k个人 long int n,k; long int Max(long int a,long int b ) { if(a>b)return a;else return b;} long int f(long int ks,long int js) { long int i; long int dp[100012]; memset(dp,0,sizeof(dp)); i=ks+2*k; dp[ks]=jf[ks];dp[ks+k]=jf[ks+k];//初始化 前 2个 连续//i从相互冲突的第3个人开始 第一用户 第二用户 for(i=ks+2*k;i<=js;i=i+k) { dp[i]=jf[i]+dp[i-2*k]; //更新从第一到当前最大 积分只要至少隔一个k就行了 所以 本积分人数加上比他小两个k积分的用户人数 dp[i-k]=Max(dp[i-k],dp[i-2*k]);//更新前一个k积分用户 } return Max(dp[i-k],dp[i-2*k]); } int main(){long int i,sum=0,s,max=0,t; scanf("%ld%ld",&n,&k); for(i=1;i<=n;i++) { scanf("%ld",&s); jf[s]++;if(max<s)max=s; } if(k==0){//为0的时候特殊处理 每个积分 只允许1个人 for(i=0;i<=max;i++)if(jf[i]!=0)sum++; }else{ for(i=0;i<=max;i++) { if(jf[i]==0)continue; t=1; while(jf[i+t*k]!=0)t++;//找出 有多少分数差k的用户(就是同时在线会冲突) if(t!=1) sum+=f(i,i+(t-1)*k);//有冲突的人 的起始用户积分与结束用户积分 else sum+=jf[i];//该积分就一个人 就不存在冲突 加上就好 t=1; while(jf[i+t*k]!=0) {jf[i+t*k]=0;t++;}//找过了就清零 }}printf("%ld\n",sum);return 0;}
AC 代码2
#include <stdio.h>#include <string.h>int jf[100012]={0};//jf[i]=k 代表积分为i的用户 有k个人int n,k;int Max( int a, int b ) { if(a>b)return a;else return b;}int f( int ks, int js){ int i;int dp,q_dp,qq_dp;qq_dp=jf[ks];q_dp=jf[ks+k];//初始化 前 2个 连续//i从相互冲突的第3个人开始 第一用户 第二用户for(i=ks+2*k;i<=js;i=i+k){dp=jf[i]+qq_dp;//更新从第一到当前最大 积分只要至少隔一个k就行了 所以 本积分人数加上比他小两个k积分的用户人数q_dp=Max(q_dp,qq_dp);//更新前一个k积分用户qq_dp=q_dp;q_dp=dp;}return Max(q_dp,qq_dp);}int main(){int i,sum=0,s,max=0,t;scanf("%d%d",&n,&k);for(i=1;i<=n;i++){ scanf("%d",&s);jf[s]++;if(max<s)max=s;}if(k==0){for(i=0;i<=max;i++)if(jf[i]!=0)sum++;}else{for(i=0;i<=max;i++){ if(jf[i]==0)continue;t=1; while(jf[i+t*k]!=0)t++;//找出 有多少分数差k的用户(就是同时在线会冲突)if(t!=1) sum+=f(i,i+(t-1)*k);//有冲突的人 的起始用户积分与结束用户积分else sum+=jf[i];//该积分就一个人 就不存在冲突 加上就好t=1; while(jf[i+t*k]!=0) {jf[i+t*k]=0;t++;}//找过了就清零}}printf("%d\n",sum);return 0;}
]]>问题 1164: 【数组的距离】
时间限制: 1Sec 内存限制: 128MB 提交: 293 解决: 144
题目描述
已知元素从小到大排列的两个数组x[]和y[],请写出一个程序算出两个数组彼此之间差的绝对值中最小的一个,这叫做数组的距离
输入
第一行为两个整数m, n(1≤m, n≤1000),分别代表数组f[], g[]的长度。
第二行有m个元素,为数组f[]。
第三行有n个元素,为数组g[]。
输出
数组的最短距离
样例输入
5 5
1 2 3 4 5
6 7 8 9 10
样例输出
1
解题思路:将先第一数组储存起来 输入第二数组时 每输入一位输入 去与第一数组元素遍历找到 当前最优数组距离(优化:因为数组元素为单调递增所以距离的结果也为单调 如果当前处理与第一数组的元素大于前面处理过的则单调性破坏break跳出不用处理后面 后面的距离必然越来越大)
注意事项:
参考代码:
#include <stdio.h>#include <stdlib.h>long int abss(long int s)//绝对值{ if(s<0)return -s; else return s;}int main(){ long int m,n,i,j,s,jl,ans,flag=0; long int f[1001]; scanf("%ld%ld",&m,&n); for(i=0;i<m;i++) scanf("%ld",&f[i]); for(i=0;i<n;i++) { scanf("%ld",&s); if(!flag) { for(j=0;j<m;j++) if(abss(s-f[j])<ans||j==0)ans=abss(s-f[j]);//求距离所以用绝对值 else break; //优化(单调性被破坏,上一个点位 极值点) if(ans<jl||i==0)jl=ans; if(jl==0||s>f[m-1])flag=1; //如果第二个数组的第一个(或任意)元素 //大于第一个数组的最后一个元素 } //那么距离就是只能jl=s-f[m-1] flag标记 后面不用处理<span class="token punctuation">}</span><span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%ld\n"</span><span class="token punctuation">,</span>jl<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
本文算法介绍 借鉴大佬博客资料整理
Manacher算法
manacher算法,我们习惯叫他 “马拉车”算法。
Manacher算法的应用范围比较狭窄,但是它的思想和拓展kmp算法有很多共通之处,所以在这里介绍一下。Manacher算法是查找一个字符串的最长回文子串的线性算法。
在介绍算法之前,首先介绍一下什么是回文串,所谓回文串,简单来说就是正着读和反着读都是一样的字符串,比如abba,noon等等,一个字符串的最长回文子串即为这个字符串的子串中,是回文串的最长的那个。
计算字符串的最长回文字串最简单的算法就是枚举该字符串的每一个子串,并且判断这个子串是否为回文串,这个算法的时间复杂度为O(n3)的,显然无法令人满意,稍微优化的一个算法是枚举回文串的中点,这里要分为两种情况,一种是回文串长度是奇数的情况,另一种是回文串长度是偶数的情况,枚举中点再判断是否是回文串,这样能把算法的时间复杂度降为O(n2),但是当n比较大的时候仍然无法令人满意,Manacher算法可以在线性时间复杂度内求出一个字符串的最长回文字串,达到了理论上的下界。
1.Manacher算法原理与实现
下面介绍Manacher算法的原理与步骤。
首先,Manacher算法提供了一种巧妙地办法,将长度为奇数的回文串和长度为偶数的回文串一起考虑,具体做法是,在原字符串的每个相邻两个字符中间插入一个分隔符,同时在首尾也要添加一个分隔符,分隔符的要求是不在原串中出现,一般情况下可以用#号。下面举一个例子:
(1)len数组简介与性质
Manacher算法用一个辅助数组Len[i]表示以字符s[i]为中心的最长回文字串的最右字符到s[i]的长度,比如以s[i]为中心的最长回文字串是s[l,r],那么Len[i]=r-i+1。
对于上面的例子,可以得出Len[i]数组为:
void init()//初始化 翻倍区 { int i; s[0]='*';s[1]='#'; for(i=0;i<le;i++) s[i*2+2]=str[i],s[i*2+3]='#'; le=le*2+2; }
Len数组有一个性质,那就是Len[i]-1就是该回文子串在原字符串S中的长度,至于证明,首先在转换得到的字符串T中,所有的回文字串的长度都为奇数,那么对于以s[i]为中心的最长回文字串,其长度就为2Len[i]-1,经过观察可知,s中所有的回文子串,其中分隔符的数量一定比其他字符的数量多1,也就是有Len[i]个分隔符,剩下Len[i]-1个字符来自原字符串,所以该回文串在原字符串中的长度就为Len[i]-1。
有了这个性质,那么原问题就转化为求所有的Len[i]。下面介绍如何在线性时间复杂度内求出所有的Len。
(2)Len数组的计算
首先从左往右依次计算Len[i],当计算Len[i]时,Lenj已经计算完毕。设mx为之前计算中最长回文子串的右端点的最大值,并且设取得这个最大值的位置为mx,分两种情况:
第二种情况: i>mx
如果i比mx还要大,说明对于中点为i的回文串还一点都没有匹配,这个时候,就只能老老实实地一个一个匹配了,匹配完成后要更新P的位置和对应的mid(id)以及Len[i]。
第一种情况:i<=mx
那么找到i相对于mid(id)的对称位置,设为j,那么如果Len[j]<mx-i,如下图:
那么说明以j为中心的回文串一定在以mid为中心的回文串的内部,且j和i关于位置mid(id)对称,由回文串的定义可知,一个回文串反过来还是一个回文串,所以以i为中心的回文串的长度至少和以j为中心的回文串一样,即Len[i]>=Len[j]。因为Len[j]<mid(id)-i,所以说i+Len[j]<mx。由对称性可知Len[i]=Len[j]。
如果Len[j]>=mid(id)-i,由对称性,说明以i为中心的回文串可能会延伸到mx之外,而大于mx的部分我们还没有进行匹配,所以要从mx+1位置开始一个一个进行匹配,直到发生失配,从而更新mx和对应的mid(id)以及Len[i]。
`第一种情况:i<=mx
asjdlsadasd
第二种情况: i>mx
如果i比mx还要大,说明对于中点为i的回文串还一点都没有匹配,这个时候,就只能老老实实地一个一个匹配了,匹配完成后要更新P的位置和对应的mid(id)以及Len[i]。
2.时间复杂度分析
Manacher算法的时间复杂度分析和Z算法类似,因为算法只有遇到还没有匹配的位置时才进行匹配,已经匹配过的位置不再进行匹配,所以对于T字符串中的每一个位置,只进行一次匹配,所以Manacher算法的总体时间复杂度为O(n),其中n为T字符串的长度,由于s的长度事实上是str的两倍,所以时间复杂度依然是线性的。
下面是算法的实现,注意,为了避免更新mid(id)的时候导致越界,我们在字符串s的前增加一个特殊字符,比如说‘’,所以算法中字符串是从1开始的。
![这里写图片描述](https://img-blog.csdn.net/20180427164243799?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxOTIzNjIy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/列题 1
问题 1209: 密码截获
时间限制: 1Sec 内存限制: 128MB 提交: 81 解决: 32
题目描述
Catcher是MCA国的情报员,他工作时发现敌国会用一些对称的密码 进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解。比如进行下列变化 ABBA->12ABBA,ABA->ABAKK,123321->51233214 。因为截获的串太长了,而且存在多种可能的情况 (abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量实在是太大了,他只能向电脑高手求助,你能帮Catcher找出最长的 有效密码串吗?
输入
测试数据有若干行字符串,包括字母,数字,符号。(字母区分大小写)
输出
与输入相对应每一行输出一个整数,代表最长有效密码串的长度。
样例输入
ABBA
12ABBA
A
ABAKK
51233214
abaaab
样例输出
4
4
1
3
6
5
#include <stdio.h>#include<string.h>#define min(a,b) a>b?b:aint le,ans=0;char str[10002];char s[20002];int len[20002]; void init()//初始化 翻倍区 { int i; s[0]='*';s[1]='#'; for(i=0;i<le;i++) s[i*2+2]=str[i],s[i*2+3]='#'; le=le*2+2; } void malache()//马拉车算法 { int mid=0,i,mx=0;//mid 代表 当前最优解对称中心 i 表示当前处理字符位置 mx 代表当前最优解的最大下标 for(i=1;i<le;i++) //(最长回文串最右端的下标) { if(i<mx)len[i]=min(len[2*mid-i],mx-i);//当前处理字符位置在当前最优范围内 直接查询对称点与当前已知情况减少操作 else len[i]=1;//否则从 1 开始 while(s[i+len[i]]==s[i-len[i]])len[i]++;//找到不是对称的点 即当前位置的回文串长度 if(len[i]+i>mx)mx=len[i]+i,mid=i;//当前比之前的大则更新 mid mx if(ans<len[i])ans=len[i];//更新最长回文串长度 } }int main(){ while(scanf("%s",&str)!=EOF) { ans=0; memset(s,0,sizeof(s)); memset(len,0,sizeof(len)); le=strlen(str); init();//初始化 翻倍区 malache(); printf("%d\n",ans-1); memset(str,0,sizeof(str));<span class="token punctuation">}</span><span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}