Tag Archives: report

[ACM] POJ2184解题报告

晚上真happy, ac了前天开始的题,还写了点东西..好久没写东西了啊 ^_<

最近做了几道背包(好像就两道吧..),自己总结一下

(为什么我突然觉得这种假装有人会看我写的东西的语气很诡异..显然很诡异啊, 赶快找点人来看..)

目前就做过01背包 完全背包 和多重背包吧.
严格的背包, 可以根据背包九讲上把除了v(1)到v(N)全附成0x80000000(负无穷), 然后按照不严格背包的思路DP
这种情况下, 如果对每一层优化, 就是最后一层只算v[V], 倒2层只从v[V-vn]..V[V]那样的优化, 这样如果严格背包得不到结果, 那就不知道不严格背包的结果了, 虽然也确实没要求..
做非严格背包也可以用严格背包的方法, 从最后的v[]数组中选出最大的即可, 但是这样不能使用每层的优化

然后像http://poj.grids.cn/problem/1276/discuss/这样不求价值只求空间占用的题目, 显然是用严格背包(不然求毛啊), 因为不用存储价值量, v[]用bool型即可, 和上面思路一样, 只是负无穷是false, 非负无穷(这个体积大小可以做到被完全占用)是true

http://poj.grids.cn/problem/2184/status/ 这个开始用的二维背包..傻逼了. 后来发现只要把s看成体积, f看成价值即可. 替换的时候比较体积和价值的和. 因为要求的东西和体积\价值有直接联系, 思维上转换一下就行

错了一天的原因是s可能是负的!! 太阴险了, 01背包刷新v[]的时候是从后像前, 否则就是完全背包. 但是如果某个物品体积是负的, 从后向前刷新v[]前面刷新过的的就会影响接下来的比较..

代码: (用个数组记录非负无穷的数组元素就能0ms吧 懒得折腾了 复杂度O(2*10^7)无压力AC…)

#include <stdio.h>
#include <stdlib.h>
#define orz 200001

int main() {
	int N,s[100],f[100];
	int a[orz];
	int k,result;

	scanf("%d",&N);
	for(int i=0;i<N;i++)
		scanf("%d%d",s+i,f+i);

	for(int i=0;i<orz;i++)
		a[i]=(int)-2e9;
	a[(orz/2)]=0;

	for(int i=0;i<N;i++) {
	    if(s[i]>0) {
            for(int j=orz-1-s[i];j>=0;j--)
                if(a[j]!=(int)-2e9 && a[j+s[i]]<a[j]+f[i])
                    a[j+s[i]]=a[j]+f[i];
	    }
        else {
            for(int j=-s[i];j<=orz-1;j++)
                if(a[j]!=(int)-2e9 && a[j+s[i]]<a[j]+f[i])
                    a[j+s[i]]=a[j]+f[i];
        }
	}

    result=(int)-2e9;
    for(int i=(orz/2);i<orz;i++) {
        if(a[i]<0)
            continue;
        result=a[i]+i>result?a[i]+i:result;
    }
	printf("%d\n",result-(orz/2));

	return 0;
}

[ACM] POJ1024解题报告

思路是board上的.. 经常是不看board没法做啊
思路非常牛B, 来自board上的apunix同学

用BFS,首先设墙和题目已给的路径上的所有点为used,剩余点为unused,然后利用BFS算出从起点到除墙以外的那些点的最短距离,然后利用BFS算出从终点到除墙以外的那些点的最短距离。
(1)判断最短路径是否唯一
如果不唯一,对于那些unused的点,必存在一个点,从起点到这点的最短距离加上从终点到这点的最短距离等于题目给出的最短距离长度
(2)判断墙是否多余
检查题目给出的墙分隔的那些点对,对一个一个被墙分隔的点对(a1,b1),(a2,b2),如果分隔它们的墙是多余的,那么从起点到(a1,b1)的最短距离加上从终点到(a2,b2)的最短距离必大于题目给出的最短距离长度pathlen,且从起点到(a2,b2)的最短距离加上从终点到(a1,b1)的最短距离也必大于pathlen,也就是起点,(a1,b1),(a2,b2),终点不可能在一个最短路径上,也就没必要用墙分隔了

一个小逻辑 有墙多余<=>存在一个墙多余
如果有m个墙是多余的,那么只考虑拿掉这m个墙中的一个其他m-1不动, 这个墙还是多余的, 因为路线完全没有依靠它

我犯了个错误.. 我以为终点一定在[w-1][h-1], 还有有人把每个点到终点/起点的距离初始化为-1, 那么如果有一个区域是封闭的会容易出错.
我是初始化为2E9, 继而中间想到的一个细节是, 这里没问题, 以后如果这些表示正无限的数相加 会超出int表示范围变成负的.. 要小心

代码:
Continue reading

[ACM] POJ1021解题报告

这是一道.. 怎么说呢 只能用龌龊来形容的题目..

折腾了两天, 重写了两遍, 第一次在题目里用链表, 有点为难自己的意思, 不过确实暂时还没想到其他可以省空间的办法.

思路:

1. 每一块用一个节点存储, 存储方式我用的点阵..   先随便找出一个点 然后dfs搜出这个点所在的区域

2. 每一块cake正过来反过来各转4个90度, 用从上到下从左到右一个点一个点比过去这样来排序, 有点傻不过还没发掘出什么具有[旋转不变性]的数学方法可以算出方向不同的cake的特征.

Continue reading

东芝T110 征服屏幕亮度

按照上一篇日志中的方法来的, 开始怎么都不成功, 然后对grub2进行了一些探索.. (文档 http://ubuntuforums.org/showthread.php?t=1195275 )我的机器上好像有bug, 无论如何update-grub都无法更新\boot\grub\grub.cfg. 这个问题是我试图更新kernel的时候发现的. 也可能是我kernel没有编译好, 但是怎么会在/etc/default/grub里加指令也不更新grub.cfg呢.. 还是觉得是bug

我的方法写在了 http://swiss.ubuntuforums.org/showthread.php?p=8767786#post8767786 这个贴子的17楼
Gnome和KDE都能完美工作~ =D

东芝T110装Ubuntu死机的问题

终于行得通了..

关键字: 东芝 T110 T115 Ubuntu 乌邦图 死机

Google进来的同学们.. 你们太走运了 你们不知道这篇文档给你们省去多少麻烦..
这个机器安装或者进入Ubuntu的时候会出现Kernel Panic
内容是

[17.529523] Kernel panic – not syncing: HwThreeWire(): CmdReg: 0XFF RE|WE bits are not clear!!
[17.529525]
[17.544365][drm:intelfb_panic] *ERROR* panic occurred, switching back to text console

我Google到了这篇帖子, 和我的机型一样, 问题一样, 并且只有这一个类似结果, 看来东芝是罪魁祸首 (也因为这型号太新了不好兼容), 死机原因是WLAN卡的驱动. 目前还没有找到不会导致Kernel panic的驱动, 他用的是方案是 ndiswrapper + the MSI version of the Windows Driver , Ndiswrapper的用处是在linux下使用Windows的网卡驱动

步骤:

首先要在BIOS下把WIFI禁用掉, 就可以成功安装进入系统了. 然后在 /etc/modprobe.d/blacklist 文件底部加上blacklist rtl8187se 阻止系统使用自带驱动(一用就崩溃).

然后安装ndiswrapper, 不要用apt-get, 有BUG, 请自己下载source来编译.. 详见我的这个帖子(4楼)
引用一下吧 防止丢了..

这是个BUG, [url=http://www.societyofrobots.com/robotforum/index.php?topic=9813.0]这个帖子[/url]的二楼提出了修复此bug的办法

[quote]Well, I fixed the ndiswrapper problem. Turns out to be a bug in the software.
open ntoskernel.h file inside ndiswrapper-1.55/driver and then change the line 878 as follows (31 is changed to 32)
old line:
Code:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
new line:
Code:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)[/quote]

即把ndiswrapper-1.55/driver/ntoskernel.h这个文件的878行作上面的修改就能成功编译了

有的同学说 你为什么不直接apt-get呢, 答案是, 直接编译的版本也有bug.. 我试了, 在[url=https://help.ubuntu.com/community/WifiDocs/Driver/Ndiswrapper]这篇文档[/url]的2.2.1下面有声明.. 不创建kernel模块, 会导致error FATAL: Module ndiswrapper not found when you run modprobe ndiswrapper

装好以后加载上面的那个驱动(ndiswrapper如何使用详见Ubuntu官网的文档) 接着 reboot 再
depmod -a && modprobe ndiswrapper
基本就可以了

WPA貌似不能用, WEP我还没试出来… 但是看人家说的可以用WEP
并且有一个方法是在这里11楼提到

1) 每次开机前先用ndiswrapper加载驱动(必须)
2) sudo rmmod ndiswrapper
3) sudo modprobe rtl8187se

这样就可以用自带驱动了, 很邪门, 但是为什么呢? 作者表示 “Don’t ask me why this works, it just does.”

下面要解决的问题是.. 屏幕亮度不能调, 插耳机外放不关.. 全是驱动问题..天啊

UPDATE:
完美运行!!

环境是KDEdesktop (好像和这个有点关系 以前也是) 原来怎么都连不上 换了上面那个驱动以后完美运行 WPA无误~~ ^^

UPDATE:
rmmod ndis/modprobe rtl以后也无误运行 真不错啊 lucky~ (呸)

看到KDE觉得这才是Ubuntu啊.. ghone(是叫这个么) 太丑太难用了..菜B     KDE大虎逼!

[ACM] POJ1014解题报告

题目:
6种球, 价值分别为1..6, 给出每种的数量, 问能不能分成价值相同的两堆

思路:
1. 将它当成背包问题来看, 包的容积一定(这里的”体积”就是球的价值, 包的容积V=球总价值的一半), 问能不能分成相等两堆即, 包是不是能装满.
2. 这里不用球背包问题中的极值, 不存在价值的概念, 所以v数组用bool型就可以.
3. 因为每种球数量有限制所以不是典型的完全背包问题(目前就看了两个..01背包和完全背包), 我对v中的每一个true它后面每i个赋值成为true, 直到这层的球耗尽. 比如开始v[0]=true v[1..V]=false, 1球的数量为10, 则第一层i循环后, v[0..10]=true v[11.V]=false
4. 3中直接赋值会对后面的计算有影响, 我很蹩脚的另外建了个列表作临时用…
5. 一次AC, 但是时间效率很低, 7XXms..都快超了(大家都爱说..都快超了), 感觉应该是算法过于繁琐..还倒来倒去的, 有空得试试O(log V/c[i])那算法
6. <背包九讲>下载 http://axlarts.com/uploads/documents/pack9lessons.doc 没作者 没写版权声明 直接转了..

代码:

 #include <cstdio>
 #include <cstring>

 int main() {
    int n[7],N,V;
    bool v[60001],t[60001];
    N=0;
    while(++N) {
        V=0;
        bool isEnd=true;
        for(int i=1;i<=6;i++) {
            scanf("%d",n+i);
            V+=n[i]*i;
            if(n[i])
                isEnd=false;
        }
        if(isEnd)
            break;

        printf("Collection #%d:\n",N);
        if(V%2) {
            printf("Can't be divided.\n\n");
            continue;
        }

        ///initialize
        V/=2;
        v[0]=true;
        memset(v+1,false,V);

        for(int i=1;i<=6;i++) {
            memset(t,false,V+1);
            for(int j=0;j<=V;j++) {
                if(!v[j])
                    continue;
                for(int k=0;k<=n[i]*i;k+=i) {
                    if((j+k)>V)
                        break;
                    t[j+k]=true;
                }
            }
            for(int j=1;j<=V;j++)
                v[j]=t[j];
        }

        if(v[V])
            printf("Can be divided.\n\n");
        else
            printf("Can't be divided.\n\n");
    }
    return 0;
 }

[ACM] POJ1061解题报告

扩展欧几里德,ap+bq=c,此题中

a=m-n;
b=-l;
c=y-x;

递归到当b=0是停止此时p一定为1,q值不定,不妨设为0,再递归上去得到p0,然后通解是

p = p0 + b/Gcd(a, b) * t
q = q0 – a/Gcd(a, b) * t

此处有一个小问题 导致了我一直不能AC
设c是gcd的n倍,那么p0*=n,然而后面b/Gcd(a, b) * t要不要乘以n呢,答案是不要,没搞清楚为什么,反正不乘就过了..

#include <cstdio>
#include <cmath>
    /*  p = p0 + b/Gcd(a, b) * t
        q = q0 - a/Gcd(a, b) * t
    45 165 63 22 10000          */

__int64 d;

void exgcd(__int64 *p,__int64 *q,__int64 a,__int64 b) {
    __int64 x,y;
    if(!b) {
        *p=1;
        *q=0;
        d=a;
        return;
    }
    exgcd(&x,&y,b,a%b);
    *p=y;
    *q=(x-a/b*y);
    return;
}

int main() {
    __int64 x,y,m,n,l,a,b,c,p,q,t;
    scanf("%I64d%I64d%I64d%I64d%I64d",&x,&y,&m,&n,&l);
    a=m-n;
    b=-l;
    c=y-x;
    exgcd(&p,&q,a,b);
    if(c%d) {
        printf("Impossible\n");
        return 0;
    }
    n=c/d;
    t=(b/d);
    t=t>0?t:-t;
    p=(n*p%t+t)%t;
    printf("%I64d\n",p);
    return 0;
}

[ACM] POJ2965 ver.2

if(a[i][j]==’+’)直接把结果矩阵里面以i,j为中心的十字全部改变bool值就好了,方便的算法
但是应该效率高啊 怎么这么慢.. 比递归慢好几倍 奇怪..

#include <cstdio>
#include <cstring>
int main() {
    char a[4][5];
    int r[32];
    int i,j,k,n=0,temp;
    for(i=0;i<4;i++)
        gets(a[i]);
    for(i=0;i<4;i++)
        for(j=0;j<4;j++) {
            temp=0;
            for(k=0;k<4;k++)
                temp+=a[i][k]/2+a[k][j]/2;
            temp-=a[i][j]/2;
            if(temp%2) {
                r[n++]=i;
                r[n++]=j;
            }
        }
    printf("%d\n",n/2);
    for(i=0;i<n;i+=2)
        printf("%d %d\n",r[i]+1,r[i+1]+1);
}

[ACM] POJ2965解题报告

爽死了 两个小时又切掉一题某人的fail!
递归大美!!! 我的思维和机器的思维真是惊人的合拍啊^^

思路:
把矩阵分成两个三角矩阵


  -+--
-  ---
--  --
-+-  -

这样然后先对上三角的第行和下三角的(左起)第列枚举,接着对上三角第行和下三角第列枚举,关键就是在从“一”进入“二”的时候 对左上角的矩形进行判断,这一个矩形是进入“二”以后再也接触不到的一个区域,如果此区域不是全部open那以后的递归就不用做了,大大提高效率 :) 自己想出来的噢~~ AC32ms 看了比绝大部分人快 也~~

debug用了大半个小时 其实只有一个错……上三角的最后一行没有进行枚举,无法得到结果,浪费那么长时间遗憾啊
debug的时候想到的技巧:因为递归层数太多显然无法一步一步调试 于是我加了这段判定代码:

if(r[0][0]&&!r[0][1]&&r[0][2]&&r[0][3]
 &&!r[1][0]&&!r[1][1]&&!r[1][2]&&!r[1][3]
 &&!r[2][0]&&!r[2][1]&&!r[2][2]&&!r[2][3]
 &&r[3][0]&&!r[3][1]&&r[3][2])
	i=1;

在i=1;上面设breakpoint就可以一步到达终点来调试了..开始多加了个&&r[3][3]因为下面的bug一直搞不出来
擦 来不及了 赶快贴了代码去学校抄作业

#include <cstdio>


bool a[4][4],r[4][4];

void change(int x,int y) {
    int i;
    for(i=0;i<4;i++) {
        a[x][i]=a[x][i]?false:true;
        a[i][y]=a[i][y]?false:true;
    }
    a[x][y]=a[x][y]?false:true;
    r[x][y]=r[x][y]?false:true;
}

bool calc(bool istop,int row,int from) {
    int i,j;

    /*TESTER
    for(i=0;i<4;i++) {
        for(j=0;j<4;j++)
            printf("%d",r[i][j]);
        printf("\n");
    }

    if(r[0][0]&&!r[0][1]&&r[0][2]&&r[0][3]
    &&!r[1][0]&&!r[1][1]&&!r[1][2]&&!r[1][3]
    &&!r[2][0]&&!r[2][1]&&!r[2][2]&&!r[2][3]
    &&r[3][0]&&!r[3][1]&&r[3][2])
        i=1;*/

    if(!istop&&row==3) {
        for(i=0;i<4;i++)
            if((!a[i][3])||(!a[3][i]))
                return false;
        return true;
    }
    if(istop) {
        if(from>3-row)
            return calc(false,row,0);
        if(calc(true,row,from+1))
            return true;
        change(row,from+row);
        if(calc(true,row,from+1))
            return true;
        change(row,from+row);
        return false;
    }
    else {
        if(from>2-row) {
            for(i=0;i<=row;i++)
                if((!a[i][row])||(!a[row][i]))
                    return false;
        return calc(true,row+1,0);
        }
        if(calc(false,row,from+1))
            return true;
        change(row+from+1,row);
        if(calc(false,row,from+1))
            return true;
        change(row+from+1,row);
        return false;
    }
}

int main() {
    int i,j,n;
    for(i=0;i<4;i++) {
        for(j=0;j<4;j++)
            a[i][j]=getchar()=='-'?true:false;
        getchar();
        r[i][j]=false;
    }
    calc(true,0,0);
    n=0;
    for(i=0;i<4;i++)
        for(j=0;j<4;j++)
            if(r[i][j])
                n++;
    printf("%d\n",n);
    for(i=0;i<4;i++)
        for(j=0;j<4;j++)
            if(r[i][j])
                printf("%d %d\n",i+1,j+1);
    return 0;
}