Author Archives: Asher

Java + MySQL 实现的图书馆管理系统

我实在想在标题后面加两个点.. 这个是课程设计..是课程设计.. 都用的C#, C#做Windows程序貌似很方便, 不过我实在不待见M$, 比较爱开源, 所以就花了一晚上整了这么一个Java + MySQL的东西出来, 之前没怎么用Java写过东西

以我的浅薄之见JDBC(就是Java得以与SQL通信的库, 与怎样的SQL通信就装一个怎样的Driver)其实是没啥大用. Linux下做MySQL应用还是以web形式好吧, 要图形界面干嘛, 反正用不到Java, Windows用.Net也比Java快, 而且也不需要跨平台..

但是反正课程设计还指望它能有什么实际用处.. 我正好练习下Java
而且虽然没用.. 但是哥确确实实是实现了跨平台.. Linux下编好compile打包成jar, 放到windows下直接运行的感觉还是不错的 嘿嘿

八百多行好像, 一小半是图形界面的代码, 用NetBeans做的图形界面, 据yzhw牛说有个叫JBuilder的做界面很不错, 不过是收费的. NetBeans我用起来也没什么问题, 就是设计的时候界面很好看, Compile出来就傻眼了..降了一个等级

总之, 这么个东西我网上没找到适合课设的源码, JDBC的实现是我Google一点一点摸索出来的, 还有点参考价值, 放出下载吧..
有BUG哟~~ 并且下面的TAB就TAB1是真的, TAB2和3都是我随便搞出来撑场子的.. 老师查的松
不过基本的数据库操作都搞出来了, 那些墨墨迹迹的功能还不是小菜

下载见下载页

[ACM] POJ 1205, 简单DP

DP就是每次在原序列右边加一个city的时候 (此时n个city) 只要看前一个状态 (n-1个city) 最右边的city的情况
也就是记录n个city时的三个状态 xxxV xxx> xxx<
xxxV 和 xxx< 的数量和就是要求的结果, xxx>是记录一下如果允许向右流水那么方案的数量
状态转移即为右图
然后dp[100]结果超过long long, 于是用BigInteger, 写这个报告的原因也是第一次用Java交OJ..

代码:


import java.math.*;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		BigInteger dp[][]=new BigInteger[101][2];
		dp[1][0]=BigInteger.ONE;
		dp[1][1]=BigInteger.ZERO;
		for(int i=2;i<=100;i++) {
			dp[i][0]=dp[i-1][0].add(dp[i-1][0]).add(dp[i-1][1]);
			dp[i][1]=dp[i-1][0].add(dp[i-1][1]);
		}
		Scanner sc=new Scanner(System.in);
		while(sc.hasNext()) {
			int a=sc.nextInt();
			System.out.println(dp[a][0].add(dp[a][1]));
		}
	}
}

[ACM] POJ 1173 解题报告, DP, 逐位确定

我表示是跟着黄伟牛混的.. 他写的报告难以称作报告.. 题目一抄写两句话代码一贴万事, 自己琢磨了好久, 记录一下, 我记性不好喜欢写的详细一点以后自己可以查.. (拓展阅读: 刘未鹏牛的<为什么你应该(从现在开始就)写博客> )

快放假了, ACM + GRE 加油, 不拼命的下场只有一个, 平庸.. 哞

第一问 total number of symbols in BC(n,k,m) 比较容易, 简单DP

dp[n][k][m]=∑dp[n-i][k-1][m]     , i∈[1,m]

第二问 yzhw口口声声“经典的逐位确定方法”..

也就是说, 我们来看 “1111010”(从0位到6位), 简单的讲从高位(0)到低位(6)每一位如果有1, 那么就看, 如果这一位是0, (继承前面的高位后) 低位能形成多少种组合, 把这个组合数加到rank中.
流程是 1[0xxxxx]能有多少组合 即求0xxxxx符合k-1和m的组合(直接用前面求出的dp数组即可, 虽然前面求的是1xxxxx, 但是和0xxxxx数量是一样的), 然后11[0xxxx]能有多少种, 遇到0跳过, 最后看11110[0x]

但是这样并不完全缜密, 我们考虑”10011000″的情况, 按上面的算法进行到第3位的时候, 100[0xxxx], 这个0xxxx是可能产生00011这种组合的, 而放入原文就变成了10000011, 0的长度就超过了. 所以我们想出来的办法是把 0-1 (不包括1到0) 交界处的那个1单独考虑, 看前面有多少位0然后详细说明. 比如100[0xxxx], xxxx只能是以1开头的, 10[0xxx], xxx只能是1xx或者01x, (11x到哪去了? 11x不是在这里的 [特殊情况] 内考虑的, 好好想一下.. 没法讲的太清楚)

代码如下, 写的时候很有自己的想法, 多推敲推敲最后的产品和yzhw的也八九不离十了.. 这个代码还是很精简很漂亮的


#include <stdio.h>
#include <string.h>
#include <algorithm>

int main() {
	int dp[34][34][34];
	memset(dp,0,sizeof(dp));
	//DP
	for(int m=1;m<=33;m++) {
		for(int i=1;i<=m;i++)
			dp[i][1][m]=1;
		for(int k=1;k<33;k++)
			for(int n=k;n<33;n++) {
				if(!dp[n][k][m])
					break;
				for(int i=1;i<=m;i++) {
					if(n+i>33)
						break;
					dp[n+i][k+1][m]+=dp[n][k][m];
				}
			}
	}

	int n,k,m;
	scanf("%d%d%d",&n,&k,&m);
	printf("%d\n",dp[n][k][m]);

	int N;
	scanf("%d",&N);
	while(N--) {
		char a[34];
		scanf("%s",a);
		char color='1';
		int rank=0;
		int kRemain=k;
		int head=0;
		for(int p=0;a[p]!='\0';p++) {
			if(color==a[p])
				continue;
			if(color=='1') {
				color='0';
				kRemain--;
				for(int i=head+1;i<p;i++)
					rank+=dp[n-i][kRemain][m];
			}
			else {
				color='1';
				kRemain--;
				for(int i=std::min(n-1,head+m);i>p;i--)
					rank+=dp[n-i][kRemain][m];
			}
			head=p;
		}
		printf("%d\n",rank);
	}

	return 0;
}

[烹饪] 20101228煎Filet牛排实验报告

器材: 普通平底锅, 木质铲子, 菜夹子..
原料: 略微腌制的Filet牛排 (以下简称单元) (大误..), 厚度目测薄处1cm 厚处1.2~1.3cm, 两块, 分两次记录数据
黑椒蘑菇汁, 总统牌黄油
目的: 对加热时间与熟度关系的数据记录
预备: 色拉油(橄榄油已耗尽..)抹锅底防止粘锅, 黄油10克每份共两份,
条件: 煎肉油温一直保持130度

第一次实验:

放入牛排, 加热20秒翻面, 目的是锁住肉汁.
继续加热20秒, 放入一份黄油, 牛排盖住黄油加速融化.
黄油融化后加热40秒, 其间保持一定频率的搅动, 使牛排始终能与黄油有充分的接触 (否则会焦..)
翻面加热20秒取出, 放入黑椒汁与肉汁搅动加热, 温度100度, 达到温度后立即取出浇上去防止水分流失

牛排情况: 切面两边靠边部分褐色, 中间为深桃红, 引用wiki百科(Steak)

Raw — Uncooked. Used in dishes like steak tartare, Carpaccio, gored gored, tiger meat and kitfo.
Seared, Blue rare or very rare — Cooked very quickly; the outside is seared, but the inside is usually cool and barely cooked. The steak will be red on the inside and barely warmed. Sometimes asked for as “blood rare” or “bloody as hell”. In the United States, this is also sometimes referred to as ‘Black and Blue’ or ‘Pittsburgh Rare’. It is common for chefs to place the steak in an oven to warm the inside of the steak. This method generally means ‘blue’ steaks take longer to cook than any other degrees.
Rare — (52 °C [125 °F] core temperature) The outside is gray-brown, and the middle of the steak is red and slightly warm.
Medium rare — (55 °C [130 °F] core temperature) The steak will have a fully red, warm center. This is the standard degree of cooking at most steakhouses, unless specified otherwise.
Medium — (60 °C [140 °F] core temperature) The middle of the steak is hot and red with pink surrounding the center. The outside is gray-brown.
Medium well done — (65 °C [150 °F] core temperature) The meat is light pink surrounding the center.
Well done — (71 °C [160 °F] and above core temperature) The meat is gray-brown throughout and slightly charred.
Overcook — (much more than 71 °C [160 °F] core temperature) The meat is dark throughout and slightly bitter.
无法准确判定, 可能是牛排太薄的原因. 不准确判定牛排薄处为3分熟(Medium rare),  厚处低于3分熟, 因为牛排太薄所以厚薄处差距较大.
厚处嚼不动又将剩下部分放进锅里加热, 40秒后翻面加热20秒, 判定为5分熟(Medium)左右. (手机没电了缺乏图片记录并且我也忘了可以留点样品下来抱歉.. 全吃了)

第二次实验

放入牛排加热20秒翻面加热20秒, 放黄油 (与第一次相同)
加热70秒翻面, 发现边上微焦并且翘起, 推测是中心比两边温度高引起的变形, 也有可能牛排不够厚没法稳住, 解决方法猜测 1. 用厚点的牛排试试 2. 用刀划一些网格阻断表面拉力的传播
看情况决定继续加热30秒(已翻面)

牛排情况: 大概七分熟(Medium Well down)或略低, 薄处接近全熟(Well down), 感觉还是”因为牛排太薄所以厚薄处差距较大”

结论

太薄了不行, 下次买3cm的试试, 我看youtube人家弄都有一块Filet简直就是长方体的.. 口感来说3分到7分都不错, 太熟完全不好吃..再往下嚼不动了

[ACM] POJ 2594 求有向图(允许路径重叠的)最小路径覆盖, Floyd + 匈牙利算法

大飞同学问我这一题, 图论的东西我是一点都没看过, 直接看了discuss
做这题用了得有十个小时.. 我可是连二分图都不知道是什么..
然后什么是二分图匹配

最小覆盖数 == 节点数 – 最大匹配数

为什么呢, 数学归纳一下, 匹配数为0时显然 最小覆盖数 == 节点数, 然后有一个二分图匹配就能把两个覆盖路径合二为一, 很简单. 具体的在ufo008ahw这里有所说明
扩展阅读: Matrix67牛有一篇文章介绍了二分图最大匹配的König定理及其证明

求二分图最大匹配匈牙利算法或者最大流(这个我还没看- -).
有向图转化成二分图很简单, 把每个节点变成两个节点(在二分图两边)一个负责入一个负责出即可

至此我们已经可以解决有向图的最小路径覆盖问题. 允许路径重叠的情况怎么办呢, 明显是要转化成不允许路径重叠的情况来依葫芦画瓢, 想要在求二分图最大匹配的过程中考虑允许重叠的情况我想过.. 没想出来, 难度吹牛逼一样.

怎样转化: 用Floyd求一下传递闭包即可, 这个我想了好久才明白, 我来说明一下
比如有向图G: 1->2->3 4->2->5
解释是: 对于任何的有重复节点的路径, 比如这里的2, 求了传递闭包以后的图就会包含1->3和4->5这两个路径, 实现”跳过去”的走法

Floyd没什么好说的, 关于匈牙利算法(初次接触)的一些细节:

1. 下面这个代码的我是看的这里, 这个数据结构和递归太牛了..做完我整个人都犀利了. 它是只记y指向x不记x指向y, 每次对x搜索可用的y, 而不是记录它们, 整个操作都简单了好多. 原文的注释写的很好
2. 代码中的visited[] 这个验证我列举了各种情况, 是正确的, 有点难度
3. 算法的原理我很清楚了. 但是代码里x和y双重循环, 为什么x和y各循环一遍就ok了我还是没有理解太透彻, 这也是匈牙利算法的精髓吧

代码点下面:
Continue reading

恢复被覆盖的MBR实现多系统引导 (在linux之后安装windows)

Windows的安装会覆盖linux的MBR, 看了看关于Grub2(linux使用的引导系统)的文档后发现Grub2可以非常方便的生成启动菜单

首先我们要进到Linux, 弄个LiveCD或者U盘引导的Linux系统盘引导进Linux(不是硬盘上的Linux).
接着执行以下步骤来恢复原Linux的MBR+Grub2 (需要root权限)

1. fdisk -l 查看本硬盘上的分区, 根据大小和文件系统大概可以判断原来的根目录/在哪个分区. 设为/dev/sdXY

2. mount /dev/sdXY /mnt

3. grub-install –root-directory=/mnt/ /dev/sdX    这样就写入Grub2和MBR了 , (注意root前面是两条扛, 我这版式有问题)

更详细点这里

重启进原Linux, sudo update-grub, 如果有”Found Windows 7 (loader) on /dev/sdxx” 就ok了.

如果不行需要自己加入Windows的引导. 我update-grub后就直接找到了win7系统, 但是下面的方法我试过且成功了.

先记一下Grub2的文件结构:

/boot/grub/grub.cfg
取代Grub1的/boot/grub/menu.lst, 最大区别是grub.cfg不应该被修改(虽然你可以), 防止出错. 这个文件是由update-grub生成的

/etc/default/grub
配置文件, 原来menu.lst里改的 现在在这里改

/etc/grub.d/
update-grub所使用的脚本, 包括菜单的外观, 以及在各个分区上寻找各种系统自动加入update-grub的脚本等等.
目录下有文件00_header 05_debian_theme 10_hurd 10_linux 20_memtest86+ 30_os-prober 40_custom, 更详细的说明点这里

其中40_custom是我们需要的, 往文件末端加入

menuentry "Windows" {
set root=(hd0,3)
chainloader +1
}

其中hd0就是sda, 如果你是sdb那就是hd1以此类推, 3是sda3的3. 这个sda3要说明一下, 用fdisk -l列出分区表, 我们要找的不是windows的安装分区, 而是它上面一个100M的分区, 这是windows单独分出来用来引导的. 我的sda3是100M, 所以这里填(hd0,3). 如果没有100M的分区那就按windows分区算吧, 至少win7默认安装是100M这样.

保存后别忘update-grub, OK

[ACM] POJ 1727 解题报告, 二分+贪心

思路和yzhw牛一样

1. 每一个event它对应的可能的cause是这个event点下面的三角形区域(这个区域是无穷大的)
2. 问 “the latest time at which the earliest cause could have occurred” 就相当于用一条平行于x轴的直线 t=t0 把这些三角形区域拦腰切断(当然, 此线必须在所有event下面), 只准在腰以上的三角形里放cause. 然后用二分求到一个恰好不能再往上移了的直线, 就成了.
3. 可行性判断, 用贪心. 三角形们和直线相交的那个区间就可以代表这个三角形, 因为放在直线以上的cause都可以垂直投影到直线上, 效果更佳.
4. 在这些所有的区间中, 要找出最少的cause个数n, 使得每个区间内都能包含至少一个的cause. 如果这个n<=m, 那么这条直线ok, 否则不ok.
5. 怎么判断呢, 引用yzhw “以区间右端点为第一关键字,左端点为第二关键字进行排序,然后每次贪心的选择当前区间的右端点作为子区间,统计要导出全部区间需要子区间的个数num。” (其实第二关键字是不用排序的, 无所谓).
6. 对应5, 举个例子

---------(A)
   ------
  -------
     --------
        -------
    ------------
                 -----(B)
.....           ......

按照右边界升序排序, 123行显然要放一个点在他们区间里, 放哪呢, “不妨”(这个词表达能力太强了)放在最右边, 即点A处. 然后我们下面所有的左边界<=A的都可以ban掉了, 因为右边界是升序排序的. 这个操作后得到的问题是最优子结构的. 然后到了第7行, A不给力了, "不妨"取一个B. 这些操作整合一下就是维护一个变量rightEdge, 一旦rightEdge不给力就取一个当前区间最右边的点, 同时更新rightEdge至这个点. 之前的错误: 对应6的例子, 我以前是按左边界优先于右边界升序排序的, 那样虽然也对但是无法处理一个区间包含另一个区间的情况, 需要filter一下, filter的过程能写成O(n), 我比较愚钝写的n^2一个case要算2分钟 - -.. 总之这个贪心记住了, 求最小覆盖数 代码点下面: Continue reading

[ACM] POJ 1887 2533 解题报告, LIS的nlogn算法..

记录到当前位置combo数为k的尾巴的最小值, 比如 1 3 2 6, 则 dp[combo]=tail 罗列为 dp[1]=1, dp[2]=2 (1,2的尾巴比1,3等小), dp[3]=6, combo最大为6. 然后再多加一位就看能不能更新前面combo数对应的tail, 让tail更小; 当然还看combo数能不能+1. 比如1 3 2 6再加个5, dp[3]就=5 (1,2,5的tail比1,2,6的tail小), 不加5加7就多一个dp[4]=7. 因为dp[combo]值相对于combo数是递增的, 所以可以二分查找实现nlogn.

这两个是买一送一的题目.. 1887的二分写的有点蛋疼.. 2533要求不能相等, 就加了个标记每次对二分的两个指针p0,p1, 和中点(p0+p1)/2看一下, 重复就continue, 不重复一样做, 省得麻烦.. 想了一下还可以前面严格<, 后面可以>=, 这样更新tail的时候就不会重复产生影响.

代码点下面:
Continue reading

[ACM] POJ 2430 解题报告, 状态压缩DP, 奶牛你太懒了..

从左到右DP, 存储哪里有奶牛以后排序, 同一个x坐标的上下奶牛合并.. 0没有 1上 2下 3都有
随着奶牛的位置x从左到右DP, 需要记录的状态是dp[i][p][k], p是在x处的奶牛圈起来的方式, 我记的是 0没圈(这就初始状态可能) 1圈上 2圈下 3两个一起圈 4两个分开圈, 记录每个可能的k和对应的面积最小值
状态转移比较麻烦.. 我是又分两个状态之间的圈圈怎样互相结合来枚举,  0不结合 1上边延伸出去 2下边 3两边一起延伸 4两边分开延伸. 应该还有更巧妙的方法.. 不想再碰这题了
172ms 直接大数组20M内存..代码点下面
Continue reading

[ACM] POJ 1230 贪心, 数据结构

挺简单的算法我没想出来..

考虑最左边的需要移除墙的列。这列是必定要移除一些墙的。
不妨移除右边界较大的那些墙。
实现的时候,可以用基数排序的方式来找到右边界较大的墙。
开两个数组如下:
map[i][j] = { 第i列中,从该列开始向右延伸,长度为j的墙的数目}
cnt[i] = {第i列中墙的数目}
这样代码比较方便,速度也快。          ——荣誉属于糯米

糯米的这个数据结构非常棒, 我做了一点改进: 糯米记录了右边还有多长的墙, 实际上只要记录右边墙的边界就可以了, 省掉一些计算和思维复杂度
所以我的代码精简一点, 看我的吧 🙂

这种题一眼看上去像DP, 我看了点东西说DP和贪心有很多相似之处, 比如都是找最优子结构. 区别在于贪心从最优子结构里选出一个或几个就行. 具体有什么区别也没太搞清楚, 感觉DP有一个图的延伸, 每个状态都可能被多次使用, 而贪心不会.

代码点下面:
Continue reading