糯米

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

POJ 1987 Distance Statistics 牛题 树的分治

     摘要: 这题很牛逼,是楼教主的《男人七题》的其中一道。求:一棵树内最短距离小于K的点对数量后来看了解题报告,原来树也是可以分治的。分:选取一条边,将一棵树分成两半,这两半的节点数要尽量相等。首先,统计个每个节点的下面有多少个节点然后,就知道每个边切断之后的情况了。选择最优的即可。治:分成两半之后,统计经过该条边的点对线段中,长度小于K的数目。Amber 大牛论文的精辟描述如下:  Divide...  阅读全文

posted @ 2010-04-25 22:30 糯米 阅读(749) | 评论 (0)编辑 收藏

POJ 1850 Code 动态规划

思路:

f[ch][len] = { 有多少个以 ch 开头,长度为 len 的字符串 }


#include <stdio.h>

__int64 dp[
16][32], sum[16], ans;

int main()
{
    
int i, j, len;
    
char str[16];

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

    
for (i = 0; i < 26; i++)
        dp[
0][i] = 1;
    
for (i = 1; i < 10; i++{
        
for (j = 25 - i; j >= 0; j--{
            dp[i][j] 
+= dp[i][j + 1];
            dp[i][j] 
+= dp[i - 1][j + 1];
        }

    }

    
for (i = 0; i < 10; i++
        
for (j = 0; j < 26; j++)
            sum[i] 
+= dp[i][j];

    scanf(
"%s", str);
    
for (len = 0; str[len]; len++)
        ans 
+= sum[len];
    ans 
-= sum[len - 1];
    j 
= 0;
    
for (i = len - 1; i >= 0; i--{
        
while (j < str[len - 1 - i] - 'a'{
            ans 
+= dp[i][j];
            j
++;
        }

        j
++;
    }

    
for (i = 0; i < len - 1; i++)
        
if (str[i] >= str[i + 1])
            ans 
= -1;
    printf(
"%I64d\n", ans + 1);

    
return 0;
}

posted @ 2010-04-22 21:52 糯米 阅读(341) | 评论 (0)编辑 收藏

POJ 1837 Balance 动态规划

思路:

力矩 = 力臂*重量。这个高中物理学过啦,呵呵。
所以如果现在有一个 3 放在 -5 的位置上,一个 4 放在 3 的位置上,那当前天平的总力矩就是 3*-5 + 4*3 = -3 了

动态规划:
从小到大依次放 weight。
f[i][j] = { 已经放了 i 个 weight,天平的总力矩为 j 时候的方案个数 }
初始化 f[0][0] = 1
状态转移:
对每个位置 x
   f[i + 1][j + W[i + 1]*x] += f[i][j]

#include <stdio.h>
#include 
<stdlib.h>

int C, G, X[24], W[24];
struct {
    
int val, tm;
}
 _dp[2][1 << 15], *dp[2= {
    
&_dp[0][_countof(_dp[0]) / 2],
    
&_dp[1][_countof(_dp[1]) / 2],
}
*cur, *pre;
int up, down;

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

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

    scanf(
"%d%d"&C, &G);
    
for (i = 1; i <= C; i++)
        scanf(
"%d"&X[i]);
    
for (i = 1; i <= G; i++)
        scanf(
"%d"&W[i]);

    dp[
1][0].tm = 1;
    dp[
1][0].val = 1;
    
for (i = 1; i <= G; i++{
        pre 
= dp[i & 1];
        cur 
= dp[(i + 1& 1];
        
for (j = down; j <= up; j++{
            
if (pre[j].tm != i)
                
continue;
            
for (k = 1; k <= C; k++{
                y 
= j + W[i]*X[k];
                
if (cur[y].tm != i + 1{
                    cur[y].tm 
= i + 1;
                    cur[y].val 
= 0;
                }

                cur[y].val 
+= pre[j].val;
                
if (y < down)
                    down 
= y;
                
if (y > up)
                    up 
= y;
            }

        }

    }

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

    
return 0;
}

posted @ 2010-04-22 21:50 糯米 阅读(130) | 评论 (0)编辑 收藏

POJ 1733 Parity game 牛题 -> 并查集+hash

思路:

这题是道好题!
假比确定了 [2, 4]、[5, 6]、[7, 8] 的奇偶性
[4, 5] 的奇偶性无法得知
[2, 6] 的奇偶性是知道的
所以只有询问的区间符合以下要求:
1. 头部和某个已知区间的头部重合
2. 尾部和某个已知区间的尾部重合
3. 区间内每一段都是已知的
才能得出结论

我只想到这一步,然后用链表写了一遍,TLE 了。上网搜解题报告,看到“并查集”三字,恍然大悟。吗的太牛逼了。

我们把首尾相接的多个已知区间归为一类。
将这多个区间的尾部的点归在同一个集合中。
它们的父亲就是最左边区间头部。
它们的权值就是从左边区间头部的到自己的这段区间的奇偶性。

插入区间 [i, j] 的时候,首先查找 i, j 对应的父亲。就是 find 操作。
如果它们的父亲相同,则表明它们处在同一个段的多个已知区间中。
那么 i, j 的权值相减,就很容易得出 [i, j] 的奇偶性了。
如果它们的父亲不同,则需要将 i, j 分别对应的区间段关联起来。也就是 union 操作。
这时候要注意判断 i, j 父亲的位置先后。因为这个 WA 了一次。

由于节点的位置分得很散,用 hash 存放。

#include <stdio.h>

#define HASH_SIZE (1 << 18)
#define NODES_NR 65536

struct node {
    
struct node *root, *next;
    
int idx, val;
}
;

struct node *hash[HASH_SIZE], nodes[NODES_NR];
int nodes_cnt;

inline 
void find(struct node *t)
{
    
static struct node *stk[NODES_NR];
    
int i;

    
for (i = 0; t->root != t; t = t->root)
        stk[i
++= t;
    
for (i--; i >= 0; i--{
        stk[i]
->val += stk[i]->root->val;
        stk[i]
->root = t;
    }

}


inline 
struct node *insert(int idx)
{
    
int h;
    
struct node *t;

    h 
= idx & (HASH_SIZE - 1);
    
for (t = hash[h]; t; t = t->next) {
        
if (t->idx == idx)
            
break;
    }

    
if (!t) {
        t 
= &nodes[nodes_cnt++];
        t
->root = t;
        t
->idx = idx;
        t
->next = hash[h];
        hash[h] 
= t;
    }

    
return t;
}


inline 
int solve(int start, int end, int val)
{
    
struct node *a, *b;

    a 
= insert(start);
    b 
= insert(end);
    find(a);
    find(b);

    
if (a->root == b->root)
        
return ((b->val - a->val) & 1== val;

    val 
-= b->val;
    val 
+= a->val;
    a 
= a->root;
    b 
= b->root;
    
if (a->idx < b->idx) {
        b
->root = a;
        b
->val = val;
    }
 else {
        a
->root = b;
        a
->val = -val;
    }


    
return 1;
}


int main()
{
    
int n, i, x, a, b;
    
char str[16];

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

    scanf(
"%d%d"&n, &x);
    
for (i = 0; i < x; i++{
        scanf(
"%d%d%s"&a, &b, str);
        
if (!solve(a, b + 1, str[0== 'o'))
            
break;
    }

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

    
return 0;
}



posted @ 2010-04-22 21:38 糯米 阅读(874) | 评论 (0)编辑 收藏

POJ 3519 Minimal Backgammon 动态规划

思路:

方程:
f[i][j] = { 还剩 i 次投 dice 的机会,此时位于第 j 个格子。这种情况下赢的概率 }

状态转移:
现在投 dice。分别考虑投到 1~6 的情况,假设最后停在 k 点。
如果 k 点是 L 点。则概率 g = f[i - 2][j]
如果 k 点是 B 点。则概率 g = f[i - 1][0]
如果 k 点是一个普通的点,则概率 g = f[i - 1][j]
f[i][j] = g[1]/6 + g[2]/6 + ... + g[6]/6

代码:

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

double prob[3][128], *p[3];
int N, T, L, B;
char map[128];

inline 
double calc(int x)
{
    
switch (map[x]) {
    
case 'B'return p[1][0];
    
case 'L'return p[0][x];
    
default : return p[1][x];
    }

}


int main()
{
    
int i, j, c, x;

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

    
while (scanf("%d%d%d%d"&N, &T, &L, &B), N) {
        memset(map, 
' 'sizeof(map));
        memset(prob, 
0sizeof(prob));
        
while (L--{
            scanf(
"%d"&i);
            map[i] 
= 'L';
        }

        
while (B--{
            scanf(
"%d"&i);
            map[i] 
= 'B';
        }

        
//prob[1][N] = 1;
        for (i = 0; i < T; i++{
            p[
2= prob[(i+2)%3];
            p[
1= prob[(i+1)%3];
            p[
0= prob[i%3];
            p[
1][N] = 1;
            
for (j = 0; j < N; j++{
                p[
2][j] = 0;
                
for (c = 6, x = j + 1; c && x < N; c--, x++)
                    p[
2][j] += calc(x) / 6;
                
for ( ; c; c--, x--)
                    p[
2][j] += calc(x) / 6;
            }

        }

        printf(
"%.6lf\n", p[2][0]);
    }


    
return 0;
}

posted @ 2010-04-21 21:57 糯米 阅读(367) | 评论 (0)编辑 收藏

POJ 3256 Cow Picnic 宽搜

思路:

这题刚开始看上去,很屌,真的。
如果用很图论的做法,就很牛逼了。
首先要把环合并为一点,然后就变成了有向无环图,然后可能用拓扑排序之类的手段解决它。
这个很难很难,反正以哥的智商是没可能想出来的。
考虑了一下,只要每头牛为起始点遍历一下图,然后统计每个点上有多少头牛能过经过就行了。
复杂度 O(NK) 还是能过的。所以就瞬间沦为一道水题了。
后来代码写出来,太爽啦 0MS,这题哥的代码是第一!

#include <stdio.h>

#define MAX_N 1024
#define MAX_E 10032

struct edge_node {
    
struct edge_node *next;
    
int b;
}
;

struct vetx_node {
    
struct edge_node *e;
    
int cows, degs;
}
;

struct edge_node edges[MAX_E];
struct vetx_node vetxs[MAX_N];
int K, N, M;
int vis[MAX_N], tm;
int queue[MAX_N], head, tail;

inline 
void push(int i, int d)
{
    
if (vis[i] == tm)
        
return ;
    vis[i] 
= tm;
    vetxs[i].degs 
+= d;
    queue[tail
++= i;
}


inline 
void pop(int *i)
{
    
*= queue[head++];
}


inline 
void bfs(int i)
{
    
int d;
    
struct edge_node *e;

    d 
= vetxs[i].cows;
    tm
++;
    head 
= tail = 0;
    push(i, d);
    
while (head != tail) {
        pop(
&i);
        
for (e = vetxs[i].e; e; e = e->next)
            push(e
->b, d);
    }

}


int main()
{
    
int i, a;

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

    scanf(
"%d%d%d"&K, &N, &M);
    
for (i = 0; i < K; i++{
        scanf(
"%d"&a);
        vetxs[a].cows
++;
    }

    
for (i = 0; i < M; i++{
        scanf(
"%d%d"&a, &edges[i].b);
        edges[i].next 
= vetxs[a].e;
        vetxs[a].e 
= &edges[i];
    }

    
for (i = 1; i <= N; i++)
        
if (vetxs[i].cows)
            bfs(i);
    a 
= 0;
    
for (i = 1; i <= N; i++)
        
if (vetxs[i].degs == K)
            a
++;
    printf(
"%d\n", a);

    
return 0;
}

posted @ 2010-04-21 21:49 糯米 阅读(261) | 评论 (0)编辑 收藏

POJ 3257 Cow Roller Coaster 背包^2

思路:

这题数据很水,所以二维背包都能过的。

#include <stdio.h>
#include 
<stdlib.h>

#define MAX_N 10032
#define MAX_B 1024
#define MAX_L 1024

struct node {
    
int x, w, f, c;
}
;

struct node in[MAX_N];
int dp[MAX_L][MAX_B], right[MAX_L];
int L, N, B;

int cmp(const void *a, const void *b)
{
    
return ((struct node *)a)->- ((struct node *)b)->x;
}


inline 
void update_max(int *a, int b)
{
    
if (b > *a)
        
*= b;
}


int main()
{
    
int i, c;
    
struct node *t;

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

    scanf(
"%d%d%d"&L, &N, &B);
    
for (i = 0; i < N; i++
        scanf(
"%d%d%d%d"&in[i].x, &in[i].w, &in[i].f, &in[i].c);
    qsort(
in, N, sizeof(in[0]), cmp);
    
    right[
0= 1;
    dp[
0][0= 1;
    
for (i = 0; i < N; i++{
        t 
= &in[i];
        
for (c = 0; c < right[t->x] && c + t-><= B; c++{
            
if (!dp[t->x][c])
                
continue;
            update_max(
&dp[t->+ t->w][c + t->c], dp[t->x][c] + t->f);
            update_max(
&right[t->+ t->w], c + t->+ 1);
        }

    }


    
for (i = c = 0; c <= B; c++)
        update_max(
&i, dp[L][c]);
    printf(
"%d\n", i - 1);

    
return 0;
}

posted @ 2010-04-21 21:43 糯米 阅读(295) | 评论 (0)编辑 收藏

POJ 1080 Human Gene Functions 动态规划

思路:

由于上下都可以加空格,这个有点崩溃。
但后来发现还是可以用动态规划做的。
假设输入的字符串分别为 A,B
f[i][j] = { 从 A[i] 和 B[j] 开始匹配,所能达到的最大值 }
假设 A[i] = G,B[j] = C
那么现在的情况就是
Gxxxxx
Cxxxxx
状态转移为
=> f[i + 1][j] + table(A[i], '-')
G...
-C..

=> f[i][j + 1] + table(B[j], '-')
-G..
C...

=> f[i + 1][j + 1] + table(A[i], B[j])
G...
C...

可以用滚动数组。

所以这样就解决了,觉得很神奇。

#include <stdio.h>

int N, M, f[2][256], *pre, *cur;
char A[256], B[256], map[256];
int tbl[5][5= {
    
5-1-2-1-3},
    
{-1,  5-3-2-4},
    
{-2-3,  5-2-2},
    
{-1-2-2,  5-1},
    
{-3-4-2-1,  0},
}
;

inline 
void swap(int **a, int **b)
{
    
int *= *a;
    
*= *b;
    
*= t;
}


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


inline 
int min(int a, int b)
{
    
return a < b ? a : b;
}


inline 
int dif(char a, char b)
{
    
return tbl[map[a]][map[b]];
}


int main()
{
    
int t, i, j;
    
    freopen(
"e:\\test\\in.txt""r", stdin);

    map[
'A'= 0;
    map[
'C'= 1;
    map[
'G'= 2;
    map[
'T'= 3;
    map[
'-'= 4;
 
    scanf(
"%d"&t);
    
while (t--{
        scanf(
"%d%s%d%s"&N, &A[1], &M, &B[1]);            
        pre 
= &f[0][0];
        cur 
= &f[1][0];
        cur[
0= 0;
        
for (i = 1; i <= M; i++)
            cur[i] 
= dif(B[i], '-'+ cur[i - 1];
        
for (i = 1; i <= N; i++{
            swap(
&pre, &cur);
            cur[
0= dif(A[i], '-'+ pre[0];
            
for (j = 1; j <= M; j++{
                cur[j] 
= dif(A[i], B[j]) + pre[j - 1];
                cur[j] 
= max(cur[j], dif(A[i], '-'+ pre[j]);
                cur[j] 
= max(cur[j], dif(B[j], '-'+ cur[j - 1]);
            }

        }

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

}

posted @ 2010-04-21 21:41 糯米 阅读(377) | 评论 (0)编辑 收藏

POJ 1170 Shopping Offers 动态规划

思路:

由于一共有5种物品,每种物品最多只能有5个,所以物品的拥有情况,可以表示为 6*6*6*6*6 中状态。
这个数好像是 7k 多,不大。
状态转移发生在有折扣的时候,如果当前的状态可以打折,那么就看打折之后是否会比现在划算就可以了。

一开始用的是取模,后来改成位操作了,快了一点,但还是很慢,不明白那些0ms怎么来的,⊙﹏⊙b汗
代码很烂,仅供参考

#include <stdio.h>

int S, B;
int price[1024], code[1024];
int offer[128], cut[128];
int ans[1 << 15];

inline 
int min(int a, int b)
{
    
return a < b ? a : b;
}


int main()
{
    
int c, k, i, j, n, t, m[5], a, b;

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

    scanf(
"%d"&B);
    t 
= 0;
    
for (i = 0; i < B; i++{
        scanf(
"%d%d%d"&c, &k, &price[i]);
        t 
|= k << (i*3);
        code[c] 
= i;
    }

    scanf(
"%d"&S);
    
for (i = 0; i < S; i++{
        scanf(
"%d"&n);
        offer[i] 
= 0;
        
while (n--{
            scanf(
"%d%d"&c, &k);
            offer[i] 
|= k << (code[c]*3);
        }

        scanf(
"%d"&cut[i]);
    }

    
for (i = 0; i <= t; i++{
        ans[i] 
= 0;
        a 
= i;
        
for (j = 0; j < B; j++{
            ans[i] 
+= price[j] * (a & 7);
            a 
>>= 3;
        }

        
for (j = 0; j < S; j++{
            a 
= i;
            b 
= offer[j];
            
for (k = 0; k < B; k++{
                
if ((a & 7< (b & 7))
                    
break;
                a 
>>= 3;
                b 
>>= 3;
            }

            
if (k < B)
                
continue;
             ans[i] 
= min(ans[i], ans[i - offer[j]] + cut[j]);
        }

    }

    printf(
"%d\n", ans[t]);

    
return 0;
}


posted @ 2010-04-21 21:32 糯米 阅读(479) | 评论 (0)编辑 收藏

POJ 1695 Magazine Delivery 动态规划

思路:

一个 O(N^3) 的动态规划,由于 N 比较小,所以没啥问题。
f[i][j][k] = { 从一开始到三辆车分别位于 i, j, k 的时候,所有车走过的距离之和的最小值 }
其中 i <= j <= k
状态转移:
1. 第一辆车走到 k + 1
2. 第二辆车走到 k + 1
3. 第三辆车走到 k + 1

注意:
  两点之间的距离跟输入一致。
  不可以计算两点间的最短距离,这样会 WA。
  这是题目没有描述清楚!


#include <stdio.h>

#define MAX_N 32
#define MAX_DIS 0x70000000

int M, N;
int D[MAX_N][MAX_N];
int dp[MAX_N][MAX_N][MAX_N];

inline 
void update(int *a, int b)
{
    
if (b < *a)
        
*= b;
}


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

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

    scanf(
"%d"&M);
    
while (M--{
        scanf(
"%d"&N);
        
for (i = 1; i <= N - 1; i++{
            
for (j = i + 1; j <= N; j++{
                scanf(
"%d"&v);
                D[i][j] 
= D[j][i] = v;
            }

        }

        
/*
        两点之间的距离跟输入一致。
        不可以计算两点间的最短距离,这样会 WA。
        这是题目没有描述清楚!
        for (k = 1; k <= N; k++)
            for (i = 1; i <= N; i++)
                for (j = 1; j <= N; j++)
                    if (D[i][k] + D[k][j] < D[i][j])
                        D[i][j] = D[i][k] + D[k][j];
        
*/

        
for (i = 1; i <= N; i++)
            
for (j = 1; j <= N; j++)
                
for (k = 1; k <= N; k++)
                    dp[i][j][k] 
= MAX_DIS;
        dp[
1][1][1= 0;
        
for (i = 1; i <= N - 1; i++{
            
for (j = 1; j <= i; j++{
                
for (k = j; k <= i; k++{
                    update(
&dp[k][i][i + 1], dp[j][k][i] + D[j][i + 1]);
                    update(
&dp[j][i][i + 1], dp[j][k][i] + D[k][i + 1]);
                    update(
&dp[j][k][i + 1], dp[j][k][i] + D[i][i + 1]);
                }

            }

        }

        v 
= MAX_DIS;
        
for (i = 1; i <= N; i++)
            
for (j = i; j <= N; j++)
                update(
&v, dp[i][j][N]);
        printf(
"%d\n", v);
    }


    
return 0;
}

posted @ 2010-04-21 21:01 糯米 阅读(199) | 评论 (0)编辑 收藏

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