糯米

TI DaVinci, gstreamer, ffmpeg
随笔 - 167, 文章 - 0, 评论 - 47, 引用 - 0
数据加载中……

POJ 1171 Letter Game 背包

思路:

它的要求是,给你几个字母,用这些字母拼几个字典里面有的单词,所有单词加起来求最高得分。
转化一下,就是个01背包问题。
由于单词的长度很短很短了,只有3~7个字母,所以总状态数很少啦。数组开到 2048 就可以AC了。

后来又搜了一下别人的解题报告哦,发现有个哥们很牛逼。
他说:单词长度范围在3--7内。所以可能的词组 只能是 3+3 或 3+4

一语惊醒脑残人。太牛逼了!

代码 150ms AC。

#include <stdio.h>

char key[] = {
    
"qwertyuiop"
    
"asdfghjkl"
    
"zxcvbnm"
}
;
int score[] = {
    
7612254135,
    
214655763,
    
7746525
}
;

int map[256], col[256], idx[256], mul[8], tot[8], cnt, hash[2048], top;

int can_add(int a, int b)
{
    
int i, ia, ib;

    
for (i = 1; i < cnt; i++{
        ia 
= (a / mul[i - 1]) % tot[i];
        ib 
= (b / mul[i - 1]) % tot[i];
        
if (ia + ib >= tot[i])
            
return 0;
    }


    
return 1;
}


int main()
{
    
int i, val, sum[256], sc;
    
char str[16];

    freopen(
"e:\\test\\in.txt""r", stdin);

    
for (i = 0; i < 26; i++)
        map[key[i]] 
= score[i];
    
    scanf(
"%s", str);
    
for (i = 0; str[i]; i++)
        col[str[i]]
++;

    cnt 
= 1;
    
for (i = 'a'; i <= 'z'; i++)
        
if (col[i]) {
            idx[i] 
= cnt;
            mul[cnt] 
= tot[cnt] = col[i] + 1;
            cnt
++;
        }


    mul[
0= 1;
    
for (i = 1; i < cnt; i++)
        mul[i] 
*= mul[i - 1];
    top 
= mul[cnt - 1];
    hash[
0= 1;

    
while (scanf("%s", str), str[0!= '.'{
        
for (i = 'a'; i <= 'z'; i++)
            sum[i] 
= 0;
        sc 
= 0;
        val 
= 0;
        
for (i = 0; str[i]; i++{
            sum[str[i]]
++;
            
if (sum[str[i]] > col[str[i]])
                
break;
            sc 
+= map[str[i]];
            val 
+= mul[idx[str[i]] - 1];
        }

        
if (str[i])
            
continue;
        
for (i = top; i >= 0; i--{
            
if (!hash[i])
                
continue;
            
if (can_add(i, val) && hash[i + val] < hash[i] + sc)
                hash[i 
+ val] = hash[i] + sc;
        }

    }


    sc 
= 0;
    
for (i = top; i >= 0; i--)
        
if (hash[i] > sc)
            sc 
= hash[i];
    printf(
"%d\n", sc - 1);

    
return 0;
}

posted @ 2010-05-10 21:37 糯米 阅读(501) | 评论 (0)编辑 收藏

POJ 1187 陨石的秘密 动态规划

#include <stdio.h>

#define MOD(x) (((x) + 11380) % 11380)

int L1, L2, L3, D, f[11][11][11][31];

inline 
int part(int ma, int mb, int mc, int md, 
                
int a, int b, int c
                )
{
    
return MOD(f[a][b][c][md - 1* f[ma - a][mb - b][mc - c][md]);
}


inline 
int calc(int ma, int mb, int mc, int md)
{
    
int a, b, c, r;

    
if (!ma && !mb && !mc)
        
return 1;

    r 
= 0;
    
if (mc) {
        
for (c = 0; c <= mc - 1; c++)
            r 
= MOD(r + part(ma, mb, mc - 1, md, 00, c));
    }

    
if (mb) {
        
for (b = 0; b <= mb - 1; b++)
            
for (c = 0; c <= mc; c++)
                r 
= MOD(r + part(ma, mb - 1, mc, md, 0, b, c));
    }

    
if (ma) {
        
for (a = 0; a <= ma - 1; a++)
            
for (b = 0; b <= mb; b++)
                
for (c = 0; c <= mc; c++)
                    r 
= MOD(r + part(ma - 1, mb, mc, md, a, b, c));
    }

    
return r;
}


int main()
{
    
int a, b, c, d;

    freopen(
"e:\\in.txt""r", stdin);

    scanf(
"%d%d%d%d"&L1, &L2, &L3, &D);

    f[
0][0][0][0= 1;
    
for (d = 1; d <= D; d++
        
for (a = 0; a <= L1; a++)
            
for (b = 0; b <= L2; b++)
                
for (c = 0; c <= L3; c++)
                    f[a][b][c][d] 
= calc(a, b, c, d);

    printf(
"%d\n", D ? MOD(f[L1][L2][L3][D] - f[L1][L2][L3][D - 1]) : 
                       MOD(f[L1][L2][L3][D])
                );

    
return 0;
}

思路:

把括号的嵌套看成是一棵树就简单点了。
这棵树的最大深度为 D。()节点下面不能有{}[]节点,[]节点下面不能有{}节点。
然后我们从上往下依次摆放节点。

考虑只有()节点的情况。
如果 f[n][d] 表示现在有n个节点需要摆放,深度小于等于d。
那么当前节点的下面可以摆 1,2 ... n 个节点。
摆完当前节点之后,剩下的在右边继续摆。
总方案数就是等于 下面的方案数*右边的方案数

考虑三种节点都有的情况,实际上只是比上面的问题复杂一点点而已。
如果 f[a][b][c][d] 表示现在有a个{}节点,b个[]节点,c个()节点需要摆放。
当前节点摆 () 的时候,下面就只能摆 (),其余的全放在右边。
当前节点摆 [] 的时候,下面就只能摆 ()[],。。。
。。。

这题的复杂度是 O(L1*L1*L2*L2*L3*L3*D)。
看上去比较大,但是可以AC的~

之前自己想的方法是 f[a][b][c][d] 表示深度等于d的方案数,而不是小于。
最后答案为 f[L1][L2][L3][D]。
复杂度多乘了一个D,就TLE了。

后来看了别人方法,发现保存深度小于等于d,这样的话会好一些。
最后答案为 f[L1][L2][L3][D] - f[L1][L2][L3][D - 1]
这方法实在牛逼!

代码:


posted @ 2010-05-06 21:56 糯米 阅读(648) | 评论 (0)编辑 收藏

KMP 演示程序

下面这个小程序,可以演示 KMP 的匹配过程。
一直没有真正理解这个算法,昨天看了下算法导论。才懂了。
确实是一个相当精辟,相当巧妙的算法。太牛逼了!

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

#define MAX_LEN 256

int tbl[MAX_LEN];
char *str = "abbbbbbb";
char *ptn = "bb";
char spc[MAX_LEN];

int main()
{
    int i, j;

    memset(spc, ' ', sizeof(spc));

    tbl[0] = 0;
    for (i = 1; ptn[i]; i++) {
        for (j = tbl[i - 1]; j && ptn[j] != ptn[i]; j = tbl[j]);
        if (ptn[j] == ptn[i])
            j++;
        tbl[i] = j;
    }
    printf("table:\n");
    for (i = 0; ptn[i]; i++) 
        printf("  %c", ptn[i]);
    printf("\n");
    for (i = 0; ptn[i]; i++)
        printf("%3d", tbl[i]);
    printf("\n");

    j = 0;
    for (i = 0; str[i]; ) {
        printf("\nmatching #%d\n", i);
        printf("%s\n", str);
        fwrite(spc, 1, i - j, stdout);
        printf("%s\n", ptn);
        fwrite(spc, 1, i, stdout);
        printf("^\n");
    
        if (str[i] == ptn[j]) {
            i++;
            j++;
            printf("ok\n");
        } else {
            if (j) 
                j = tbl[j - 1];
            else
                i++;
            printf("jumped to %d\n", j);
        }
        if (!ptn[j])
            printf("matched at %d\n", i);
    }

    return 0;
}



输出:
table:
  b  b
  0  1

matching #0
abbbbbbb
bb
^
jumped to 0

matching #1
abbbbbbb
 bb
 ^
ok

matching #2
abbbbbbb
 bb
  ^
ok
matched at 3

matching #3
abbbbbbb
 bb
   ^
jumped to 1

matching #3
abbbbbbb
  bb
   ^
ok
matched at 4

matching #4
abbbbbbb
  bb
    ^
jumped to 1

matching #4
abbbbbbb
   bb
    ^
ok
matched at 5

matching #5
abbbbbbb
   bb
     ^
jumped to 1

matching #5
abbbbbbb
    bb
     ^
ok
matched at 6

matching #6
abbbbbbb
    bb
      ^
jumped to 1

matching #6
abbbbbbb
     bb
      ^
ok
matched at 7

matching #7
abbbbbbb
     bb
       ^
jumped to 1

matching #7
abbbbbbb
      bb
       ^
ok
matched at 8

posted @ 2010-04-29 12:48 糯米 阅读(413) | 评论 (0)编辑 收藏

[转]很有感觉的一篇文章

二十年前的那碗馄饨

   这天,白云酒楼里来了两位客人,一男一女,四十岁上下,穿着不俗,男的还拎着一个旅行包,看样子是一对出来旅游的夫妻。

    服务员笑吟吟地送上菜单。男的接过菜单直接递女的,说:“你点吧,想吃什么点什么。”女的连看也不看一眼,抬头对服务员说:“给我们来碗馄饨就行了!”

    服务员一怔,哪有到白云酒楼吃馄饨的?再说,酒楼里也没有馄饨卖啊。她以为自己没听清楚,不安的望着那个女顾客。女人又把自己的话重复了一遍,旁边的男人这时候发话了:“吃什么馄饨,又不是没钱?”

    女人摇摇头说:“我就是要吃馄饨!”男人愣了愣,看到服务员惊讶的目光,很难为情地说:“好吧。请给我们来两碗馄饨。”

    “不!”女人赶紧补充道,”只要一碗!”男人又一怔,一碗怎么吃?女人看男人皱起了眉头,就说:“你不是答应的,一路上都听我的吗?”

    男人不吭声了,抱着手靠在椅子上。旁边的服务员露着了一丝鄙夷的笑意,心想:这女人抠门抠到家了。上酒楼光吃馄饨不说,两个人还只要一碗。她冲女人撇了撇嘴:“对不起,我们这里没有馄饨卖,两位想吃还是到外面大排挡去吧!”

    女人一听,感到很意外,想了想才说:“怎么会没有馄饨卖呢?你是嫌生意小不愿做吧?”

    这会儿,酒楼老板张先锋恰好经过,他听到女人的话,便冲服务员招招手,服务员走过去埋怨道:“老板,你看这两个人,上这只点馄饨吃,这不是存心捣吗?”

    店老板微微一笑,冲她摆摆手。他也觉得很奇怪:看这对夫妻的打扮,应该不是吃不起饭的人,估计另有什么想法。不管怎样,生意上门,没有往外推的道理。

    他小声吩咐服务员:“你到外面买一碗馄饨回来,多少钱买的,等会结帐时多收一倍的钱!”说完他拉张椅子坐下,开始观察起这对奇怪的夫妻。

    过了一会,服务员捧回一碗热气腾腾的馄饨,往女人面前一放,说:“请两位慢用。”


    看到馄饨,女人的眼睛都亮了,她把脸凑到碗面上,深深地细了一口气,然后,用汤匙轻轻搅拌着碗里的馄饨,好象舍不得吃,半天也不见送到嘴里。

   男人瞪大眼睛看者女人,又扭头看看四周,感觉大家都在用奇怪的眼光盯着他们,顿感无地自容,恨恨地说道:“真搞不懂你在搞什么,千里迢迢跑来,就为了吃这碗馄饨?”

    女人抬头说道:“我喜欢!”

    男人一把拿起桌上的菜单:“你爱吃就吃吧,我饿了一天了,要补补。”他便招手叫服务员过来,一气点了七八个名贵的菜。

    女人不急不慢,等男人点完了菜。这才淡淡地对服务员说:“你最好先问问他有没有钱,当心他吃霸王餐。”

    没等服务员反应过来,男人就气红了脸:“放屁!老子会吃霸王餐?老子会没钱?”他边说边往怀里摸去,突然”咦”的一声:“我的钱包呢?”他索性站了起来,在身上又是拍又是捏,这一来竟然发现手机也失踪了。男人站着怔了半晌,最后将眼光投向对面的女人。


    女人不慌不忙地说道:“迩别瞎忙活了,钱包和手机我昨晚都扔到河里了。”

    男人一听,火了:“你疯了!”女人好象没听见一样,继续缓慢的搅拌着碗里的馄饨。男人突然想起什么,拉开随身的旅行包,伸手在里面猛掏起来。

    女人冷冷说了句:“别找了,你的手表,还有我的戒指,咱们这次带出来所有值钱的东西,我都扔河里了。我身上还有五块钱,只够买这碗馄饨了!”

    男人的脸刷地白了,一屁股坐下来,愤怒的瞪着女人:“你真是疯了,你真是疯了!咱们身上没有钱,那么远的路怎么回去啊?”

    女人却一脸平静,不温不火地说:“你急什么?再怎么着,我们还有两条腿,走着走着就到家了。”

    男人沉闷的哼了一声。女人继续说道:“二十年前,咱们身上一分钱也没有,不也照样回到家了吗?那时侯的天。比现在还冷呢!”

    男人听了这句,不由的瞪直了眼:“你说,你说什么?”女人问:“你真的不记得了?”男人茫然的摇摇头。

    女人叹了口气:“看来,这些年身上有了几个钱,迩就真的把什么都忘了。二十年前,咱们第一次出远门做生意,没想到被人骗了个精光,连回家的路费都没了。经过这里的时候,你要了一碗馄饨给我吃,我知道,那时候你身上就剩下五毛钱了……”

    男人听到这里,身子一震,打量了四周:“这,这里……”女人说:“对,就是这里,我永远也不会忘记的,那时它还是一间又小又破的馄饨店。”

    男人默默地低下头,女人转头对在一旁发愣的服务员道:“姑娘,请给我再拿只空碗来。”

    服务员很快拿来了一只空碗,女人捧起面前的馄饨,拨了一大半到空碗里,轻轻推到男人面前:“吃吧,吃完了我们一块走回家!”

    男人盯着面前的半碗馄饨,很久才说了句:“我不饿。”女人眼里闪动着泪光,喃喃自语:“二十年前,你也是这么说的!”说完,她盯着碗没有动汤匙,就这样静静地坐着。

    男人说:“你怎么还不吃?”女人又哽咽了:“二十年前,你也是这么问我的。我记得我当时回答你。要吃就一块吃,要不吃就都不吃,现在,还是这句话!”

    男人默默无语,伸手拿起了汤匙。不知什么原因,拿着汤匙的手抖得厉害,舀了几次,馄饨都掉下来。最后,他终于将一个馄饨送到了嘴里,使劲一吞,整个都吞到了肚子里。当他舀第二个馄饨的时候,眼泪突然”叭嗒`叭嗒”往下掉。

    女人见他吃了,脸上露出了笑容,也拿起汤匙开始吃。馄饨一进嘴,眼泪同时滴进了碗里。这对夫妻就这和着眼泪把一碗馄饨分吃完了。

    放下汤匙,男人抬头轻声问女人:“饱了么?”

    女人摇了摇头。男人很着急,突然他好象想起了什么,弯腰脱下一只皮鞋,拉出鞋垫,手往里面摸,没想到居然摸出了五块钱。他怔了怔,不敢相信地瞪着手里的钱。


    女人微笑的说道:“二十年前,你骗我说只有五毛钱了,只能买一碗馄饨,其实呢,你还有五毛钱,就藏在鞋底里。我知道,你是想藏着那五毛钱,等我饿了的时候再拿出来。后来你被逼吃了一半馄饨,知道我一定不饱,就把钱拿出来再买了一碗!”顿了顿,她又说道,”还好你记得自己做过的事,这五块钱,我没白藏!”

    男人把钱递给服务员:“给我们再来一碗馄饨。”服务员没有接钱,快步跑开了,不一会,捧回来满满一大碗馄饨。

    男人往女人碗里倒了一大半:“吃吧,趁热!”

    女人没有动,说:“吃完了,咱们就得走回家了,你可别怪我,我只是想在分手前再和你一起饿一回。苦一回!”

    男人一声不吭,低头大口大口吞咽着,连汤带水,吃得干干净净。他放下碗催促女人道:“快吃吧,吃好了我们走回家!”

    女人说:“迩放心,我说话算话,回去就签字,钱我一分不要,你和哪个女人好,娶个十个八个,我也不会管你了……”

    男人猛地大声喊了起来:“回去我就把那张离婚协议书烧了,还不行吗?”说完,他居然号啕大哭,”我错了,还不行吗?我脑袋抽筋了,还不行吗?”

    女人面带笑容,平静地吃完了半碗馄饨,然后对服务员:“姑娘,结帐吧。”,

    一直在旁观看的老板张先锋猛然惊醒,快步走了过来,挡住了女人的手,却从身上摸出了两张百元大钞递了过去:“既然你门回去就把离婚协议书烧了,为什么还要走路回家呢?”

    男人和女人迟疑地看着店老板,店老板微笑道:“咱们都是老熟人了,你门二十年前吃的馄饨,就是我卖的,那馄饨就是我老婆亲手做的!”说罢,他把钱硬塞到男人手中,头也不回地走了……

    店老板回到办公室,从抽屉取出那张早已拟好的离婚协议书,怔怔地看了半晌,喃喃自语地说:“看来,我的脑袋也抽筋了……”

    分手时想想以前,那个陪你甘苦与共的人,一路走来。其实你们的故事并不短。时间慢慢过去,那些感动却一点一点封存。其实最疼你的人不是那个甜言蜜语哄你开心的人。也许就是在鞋底藏5元钱。在最后的时候把最后一点东西省着给你吃,却说不饿的人……

posted @ 2010-04-29 11:58 糯米 阅读(489) | 评论 (0)编辑 收藏

POJ 2009 Moo University - Emergency Pizza Order 无耻贪心解法

这题能不能贪心,是很难说的。。
因为没有能什么证明贪心是对的,但也没找到什么反例。
代码写出来,WA了。
但总觉得是对的,因为吗的实在找不到反例。
结果找到数据测了下,果然十个过了九个。。
你看,如果这是NOIP,跟满分都没啥区别的对吧。我已经满足了。。
没过的那组,比较大,肉眼看不出是啥问题。
想了下,给排序加多了一个判断,然后那组数据就过了。。
然后提交,吗的还上榜了。。无语。

这样做比较无耻,网上有人说用最大流做,不理解。下次想一想。

思路:
如果牛喜欢的种类个数小于 K,那这种牛是无法满足的。。
把牛按照喜欢的种类个数排序,先处理小的。
就是用组合数枚举每一种可能的 pizza 情况。
用 hash 保存这些情况。

代码:
#include <stdio.h>
#include 
<stdlib.h>

#define HASH_SIZE 65536

struct cow_node {
    
int val, cnt;
}
;

int C, T, K, ans;
struct cow_node cows[1024];
int hash[HASH_SIZE];

int cmp(const void *a, const void *b)
{
    
if (((struct cow_node *)a)->cnt == ((struct cow_node *)b)->cnt)
        
return ((struct cow_node *)a)->val - ((struct cow_node *)b)->val;
    
return ((struct cow_node *)a)->cnt - ((struct cow_node *)b)->cnt;
}


inline 
int insert(int val)
{
    
int i, h;

    h 
= val & (HASH_SIZE - 1);
    
for (i = h + 1; i != h && hash[i] && hash[i] != val; )
        i 
= (i + 1& (HASH_SIZE - 1);
    
if (i == h || hash[i] == val)
        
return 0;
    hash[i] 
= val;
    
return 1;
}


inline 
int calc(struct cow_node *t)
{
    
int arr[32], map[32], i, j, val;

    
for (i = j = 0; i < 32; i++)
        
if (t->val & (1 << i))
            map[j
++= (1 << i);
    
for (i = 0; i < K; i++)
        arr[i] 
= i;
    
while (1{
        val 
= 0;
        
for (i = 0; i < K; i++)
            val 
|= map[arr[i]];
        
if (insert(val))
            
return 1;
        
for (i = K - 1; i >= 0 && arr[i] == i + t->cnt - K; i--);
        
if (i < 0)
            
break;
        arr[i]
++;
        
for (i++; i < K; i++)
            arr[i] 
= arr[i - 1+ 1;
    }


    
return 0;
}


int main()
{
    
int i, j, k;

    freopen(
"e:\\test\\in.txt""r", stdin);

    scanf(
"%d%d%d"&C, &T, &K);
    
for (i = 0; i < C; i++{
        scanf(
"%d"&cows[i].cnt);
        cows[i].val 
= 0;
        
for (j = 0; j < cows[i].cnt; j++{
            scanf(
"%d"&k);
            k
--;
            cows[i].val 
|= 1 << k;
        }

        
if (cows[i].cnt < K) {
            i
--; C--;
            
continue;
        }

    }

    qsort(cows, C, 
sizeof(cows[0]), cmp);

    
for (i = 0; i < C; i++
        ans 
+= calc(&cows[i]);
    printf(
"%d\n", ans);

    
return 0;
}


posted @ 2010-04-27 14:25 糯米 阅读(789) | 评论 (0)编辑 收藏

POJ 2111 Millenium Leapcow 动态规划

思路:

先按棋盘上的值从大到小排序。
然后先解决值大的,再解决值小的。
注意路径的比较。应该很容易WA的。

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

using namespace std;

#define MAX_N 512

struct seq_node {
    
short y, x;
}
;
struct map_node {
    
int val, cnt;
    
struct map_node *pre;
}
;
struct map_node map[MAX_N][MAX_N], *ans;
struct seq_node seq[MAX_N*MAX_N];
int N;

int cmp_seq(const void *a, const void *b)
{
    
return    map[((struct seq_node *)a)->y][((struct seq_node *)a)->x].val - 
            map[((
struct seq_node *)b)->y][((struct seq_node *)b)->x].val;
}


inline 
int cmp_path(struct map_node *a, struct map_node *b)
{
    
while (a && b) {
        
if (a->val != b->val)
            
return a->val - b->val;
        a 
= a->pre;
        b 
= b->pre;
    }

    
return 0;
}


inline 
void update(struct map_node *a, int y2, int x2)
{
    
struct map_node *= &map[y2][x2];

    
if (y2 < 0 || y2 >= N || x2 < 0 || x2 >= N)
        
return ;    
    
if (b->val > a->val && 
        (b
->cnt > a->cnt || b->cnt == a->cnt && cmp_path(b, a->pre) < 0)
        ) 
    
{
        a
->cnt = b->cnt;
        a
->pre = b;
    }

}


int main()
{
    
int x, y, i;
    
struct seq_node *t;
    
struct map_node *m;

    freopen(
"e:\\test\\in.txt""r", stdin);

    scanf(
"%d"&N);
    i 
= 0;
    
for (y = 0; y < N; y++{
        
for (x = 0; x < N; x++{
            scanf(
"%d"&map[y][x].val);
            seq[i].y 
= y;
            seq[i].x 
= x;
            i
++;
        }

    }

    qsort(seq, N
*N, sizeof(seq[0]), cmp_seq);

    
for (t = &seq[N*- 1]; t >= seq; t--{
        m 
= &map[t->y][t->x];
        update(m, t
->- 2, t->+ 1);
        update(m, t
->+ 2, t->+ 1);
        update(m, t
->- 2, t->- 1);
        update(m, t
->+ 2, t->- 1);
        update(m, t
->- 1, t->+ 2);
        update(m, t
->+ 1, t->+ 2);
        update(m, t
->- 1, t->- 2);
        update(m, t
->+ 1, t->- 2);
        m
->cnt++;
        
if ((!ans || m->cnt > ans->cnt) ||
            (m
->cnt == ans->cnt && cmp_path(m, ans) < 0)
            ) 
            ans 
= m;
    }


    printf(
"%d\n", ans->cnt);
    
while (ans) {
        printf(
"%d\n", ans->val);
        ans 
= ans->pre;
    }


    
return 0;
}

posted @ 2010-04-27 14:14 糯米 阅读(398) | 评论 (0)编辑 收藏

POJ 3169 Layout 差分约束

思路:

差分约束是个很神奇的东西,能将下面这种类型的不等式约束问题:
d[1] - d[2] <= a
d[4] - d[7] <= b
...
求 d[x] 的最大/小值
转化为最短路径的问题,真吗的太牛逼了。
原理呢,就是一个图求出单源最短路径之后。
两点之间的关系必然是满足 d[u] + w[u,v] >= d[v] 的,没法再松弛了。

对于这道题,有两种约束:
1. 输入里指明的约束
2. d[1] <= d[2] <= d[3] .... <= d[N]

建立完这两种约束之后,然后spfa求一下最短路径。
如果有负环,就输出 -1
如果不连通,就输出 -2

#include <stdio.h>

#define MAX_DIS 1000000032
#define MAX_N 1024
#define MAX_EDGES 65536

struct edge_node {
    
int i, w;
    
struct edge_node *next;
}
;

int N, ML, MD;
struct edge_node edges[MAX_EDGES], *map[MAX_N];
int edges_cnt;
int D[MAX_N], queue[MAX_N], head, tail, vis[MAX_N], tm, cnt[MAX_N];

inline 
void add_edge(int a, int b, int w)
{
    
struct edge_node *= &edges[edges_cnt++];

    e
->= b;
    e
->= w;
    e
->next = map[a];
    map[a] 
= e;
}


inline 
int push(int i, int d)
{
    
if (d >= D[i])
        
return 0;
    D[i] 
= d;
    
if (vis[i] == tm)
        
return 0;
    vis[i] 
= tm;
    cnt[i]
++;
    
if (cnt[i] >= N)
        
return 1;
    queue[tail
++= i;
    tail 
&= MAX_N - 1;
    
return 0;
}


inline 
int spfa()
{
    
int i;
    
struct edge_node *e;

    
for (i = 1; i <= N; i++
        D[i] 
= MAX_DIS;
    tm
++;
    head 
= tail = 0;
    push(
10);
    
while (head != tail) {
        i 
= queue[head++];
        head 
&= MAX_N - 1;
        vis[i] 
= 0;
        
for (e = map[i]; e; e = e->next) 
            
if (push(e->i, D[i] + e->w))
                
return 1;
    }


    
return 0;
}


int main()
{
    
int a, b, w, i;

    freopen(
"e:\\test\\in.txt""r", stdin);

    scanf(
"%d%d%d"&N, &ML, &MD);
    
while (ML--{
        scanf(
"%d%d%d"&a, &b, &w);
        add_edge(a, b, w);
    }

    
while (MD--{
        scanf(
"%d%d%d"&a, &b, &w);
        add_edge(b, a, 
-w);
    }

    
for (i = 2; i <= N; i++)
        add_edge(i, i 
- 10);

    
if (spfa())
        a 
= -1;
    
else
        a 
= (D[N] == MAX_DIS) ? -2 : D[N];
    printf(
"%d\n", a);

    
return 0;
}

posted @ 2010-04-27 14:11 糯米 阅读(441) | 评论 (0)编辑 收藏

POJ 3188 Cellphones 枚举+hash

思路:

这题是暴力枚举,哈哈。
枚举每一种可能的字母分配情况。
然后再对每个单词求出按键序列以后,对按键序列进行 hash,用普通的字串hash函数即可。
最后就可以统计具有唯一按键序列的单词个数了。

这种做法还是相当快的,代码跑到了450ms 。是第一哦!

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

#define MAX_D 1024
#define HASH_SIZE 65536

struct node {
    
struct node *next;
    
int val, cnt;
}
;

int B, L, D;
int map[256], ans[256], best;
char dict[MAX_D][16];
struct node nodes[MAX_D], *hash[HASH_SIZE];
int nodes_cnt;
int vis[HASH_SIZE], tm;

inline 
void calc()
{
    
int i, h, val, uni;
    
char *s;
    
struct node *t;

    tm
++;
    nodes_cnt 
= 0;
    
for (i = 0; i < D; i++{
        val 
= 0;
        
for (s = dict[i]; *s; s++
            val 
= val*31 + map[*s] + 'a';
        h 
= val & (HASH_SIZE - 1);
        
if (vis[h] != tm) {
            vis[h] 
= tm;
            hash[h] 
= NULL;
        }

        
for (t = hash[h]; t; t = t->next)
            
if (t->val == val)
                
break;
        
if (!t) {
            t 
= &nodes[nodes_cnt++];
            t
->val = val;
            t
->cnt = 0;
            t
->next = hash[h];
            hash[h] 
= t;
        }

        t
->cnt++;
    }


    uni 
= 0;
    
for (i = 0; i < nodes_cnt; i++)
        
if (nodes[i].cnt == 1)
            uni
++;

    
if (uni > best) {
        best 
= uni;
        memcpy(ans, map, 
sizeof(map));
    }

}


void dfs(int b, int l)
{
    
int i, cnt;

    cnt 
= L - l - (B - b) + 1;
    
for (i = 0; i < cnt; i++)
        map[l 
+ 'A' + i] = b;
    
    
if (b == B - 1{
        calc();
        
return ;
    }


    
for (i = cnt; i >= 1; i--)
        dfs(b 
+ 1, l + i);
}


int main()
{
    
int i;

    freopen(
"e:\\test\\in.txt""r", stdin);

    scanf(
"%d%d%d"&B, &L, &D);
    
for (i = 0; i < D; i++)
        scanf(
"%s", dict[i]);
    dfs(
00);
    printf(
"%d\n", best);
    
for (i = 'A'; i < 'A' + L; i++{
        
if (ans[i] != ans[i - 1])
            putchar(
'\n');
        putchar(i);
    }

    putchar(
'\n');

    
return 0;
}

posted @ 2010-04-26 19:28 糯米 阅读(617) | 评论 (1)编辑 收藏

POJ 3186 Treats for the Cows 动态规划

思路:


f[倒数第几天][队列头的位置] = { 该状态下所产生的最大值 }
状态转移:
f[i][j] = max {
    V[j + i]*(N - i) + f[i - 1][j],
    f[i - 1][j + 1] + V[j]*(N - i)
}

代码:
#include <stdio.h>

inline 
int max(int a, int b)
{
    
return a > b ? a : b;
}


int N, V[2048], f[2][2048], *cur, *pre;

int main()
{
    
int i, j;

    freopen(
"e:\\test\\in.txt""r", stdin);

    scanf(
"%d"&N);
    
for (i = 0; i < N; i++{
        scanf(
"%d"&V[i]);
        f[
1][i] = V[i]*N;
    }

    
for (i = 1; i < N; i++{
        pre 
= f[i & 1];
        cur 
= f[(i + 1& 1];
        
for (j = 0; j < N - i; j++
            cur[j] 
= max(pre[j] + V[j + i]*(N - i), pre[j + 1+ V[j]*(N - i));
    }

    printf(
"%d\n", cur[0]);

    
return 0;
}

posted @ 2010-04-26 16:36 糯米 阅读(457) | 评论 (0)编辑 收藏

POJ 3189 Steady Cow Assignment 二分图的多重匹配

思路:

这题完全不懂,看了这份大牛的解题报告
http://hi.baidu.com/winterlegend/blog/item/2411981e8fd0ed6bf724e45e.html
发现吗的太牛逼了!

首先二分图匹配,正常情况下,都是单个单个的点这样匹配、
但是像这道题,右边的点一个可以匹配好几个左边的点。也是用匈牙利算法,不过要做少少修改。

枚举答案的时候,有两种方法:
一个是移动区间的方法。复杂度O(B)。注意,只移动区间右边的时候不用重新匹配,只需要接着上次没匹配完的继续匹配就行了
一个是二分法。复杂度 O(B lgB)
由于数据的问题,这两种方法时间相差无几。在 16ms 和 32ms 之间。

#include <stdio.h>

struct barn {
    
int link[1024], cnt, vis, cap;
}
;
struct cow {
    
int rank[32];
}
;

struct barn barns[32];
struct cow cows[1024];
int start, end, last_pos;
int N, B, tm;

int dfs(int c)
{
    
int i, j;
    
struct barn *b;

    
for (i = start; i <= end; i++{
        b 
= &barns[cows[c].rank[i]];
        
if (b->vis == tm)
            
continue;
        b
->vis = tm;
        
if (b->cnt < b->cap) {
            b
->link[b->cnt++= c;
            
return 1;
        }

        
for (j = 0; j < b->cap; j++)
            
if (dfs(b->link[j])) {
                b
->link[j] = c;
                
return 1;
            }

    }

    
return 0;
}


inline 
void init()
{
    
int i;

    
for (i = 1; i <= B; i++)
        barns[i].cnt 
= 0;
    last_pos 
= 1;
}


inline 
int match()
{
    
int i, j;

    
for (i = last_pos; i <= N; i++{
        tm
++;
        
if (!dfs(i))
            
break;
    }

    last_pos 
= i;
    
return i > N;
}


int main()
{
    
int i, j, ans;

    freopen(
"e:\\test\\in.txt""r", stdin);

    scanf(
"%d%d"&N, &B);
    
for (i = 1; i <= N; i++)
        
for (j = 1; j <= B; j++)
            scanf(
"%d"&cows[i].rank[j]);
    
for (i = 1; i <= B; i++)
        scanf(
"%d"&barns[i].cap);
    
#if 0
    
// O(B)
    ans = B;
    start 
= end = 1;
    
while (start <= B && end <= B) {
        init();
        
while (end <= B && !match())
            end
++;
        
if (end - start + 1 < ans)
            ans 
= end - start + 1;
        start
++;
    }

#else
    
// O(B*lgB)
    int l, r, m;

    l 
= 1;
    r 
= B;
    
while (l <= r) {
        m 
= (l + r) / 2;
        
for (start = 1; start <= B - m + 1; start++{
            end 
= start + m - 1;
            init();
            
if (match())
                
break;
        }

        
if (start == B - m + 2{
            
// failed
            l = m + 1;
        }
 else 
            r 
= m - 1;
    }

    ans 
= r + 1;
#endif

    printf(
"%d\n", ans);

    
return 0;
}

posted @ 2010-04-26 15:34 糯米 阅读(544) | 评论 (0)编辑 收藏

仅列出标题
共17页: First 3 4 5 6 7 8 9 10 11 Last