糯米

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

POJ 3038 Flying Right 贪心

这题不懂做,一开始想了一个动态规划的方法,复杂度很高。估计得几百ms。
看status,觉得肯定有很低复杂度的方法。
然后看了 Discuss ,看到某位大牛说的贪心方法,顿时恍然大悟,吗的实在太牛逼了。
这位大牛的解法如下:
想象自己是一个黑一日游的司机:
1.如果有乘客要上车,那么就让他上,收钱!
2.如果超载了,把距目的地最远的几个乘客踢下去,退钱。
3.行驶到下一站

照着这个方法编码,一开始速度很慢,后来改成用一个队列来维护车上的乘客,速度就很快了,还飚上榜了。

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

#define MAX_N 10032
#define MAX_K 50032

struct slot_node {
    
int end, cap;
    
struct slot_node *next;
}
;
struct stat_node {
    
int idx[MAX_N], cnt[MAX_N], head, tail, tot;
}
;
struct slot_node *start[2][MAX_N], slots[MAX_K*2];
struct stat_node stat[2];
int K, N, C, left, right, slots_cnt, ans;

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


inline 
void ins(int a, int b, int c, int d)
{
    
struct slot_node *t;

    
if (b > right)
        right 
= b;
    
if (a < left)
        left 
= a;
    t 
= &slots[slots_cnt++];
    t
->next = start[d][a];
    t
->end = b;
    t
->cap = c;
    start[d][a] 
= t;
}


inline 
void off(int d, int i)
{
    
struct stat_node *= &stat[d];

    
if (t->head == t->tail || t->idx[t->head] != i) 
        
return ;
    ans 
+= t->cnt[t->head];
    t
->tot -= t->cnt[t->head];
    t
->head++;
}


inline 
void del(struct stat_node *t)
{
    
int c;

    
while (t->tot > C) {
        c 
= min(t->tot - C, t->cnt[t->tail - 1]);
        t
->cnt[t->tail - 1-= c;
        t
->tot -= c;
        
if (!t->cnt[t->tail - 1])
            t
->tail--;
    }

}


inline 
void add(struct stat_node *t, int cap, int end)
{
    
int i, j;

    t
->tot += cap;

    
for (i = t->tail - 1; i >= t->head; i--{
        
if (t->idx[i] == end) {
            t
->cnt[i] += cap;
            
return ;
        }
 else if (t->idx[i] < end)
            
break;
    }

    i
++;
    t
->tail++;
    
for (j = t->tail - 1; j > i; j--{
        t
->idx[j] = t->idx[j - 1];
        t
->cnt[j] = t->cnt[j - 1];
    }

    t
->idx[i] = end;
    t
->cnt[i] = cap;
}


inline 
void on(int d, int i)
{
    
struct slot_node *s;
    
struct stat_node *= &stat[d];

    
for (s = start[d][i]; s; s = s->next) 
        add(t, s
->cap, s->end);
    del(t);
}


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

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

    scanf(
"%d%d%d"&K, &N, &C);
    left 
= N;
    
for (i = 0; i < K; i++{
        scanf(
"%d%d%d"&a, &b, &c);
        
if (a > b) 
            ins(N 
- a, N - b, c, 1);
        
else
            ins(a, b, c, 
0);
    }


    
for (i = left; i <= right; i++{
        off(
0, i);
        off(
1, i);
        on(
0, i);
        on(
1, i);
    }

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

    
return 0;
}


posted @ 2010-04-12 16:37 糯米 阅读(436) | 评论 (0)编辑 收藏

POJ 3046 Ant Counting 动态规划

思路:

f[a][b] = { 种类数目为 a,蚂蚁数目为 b 时候的方案总数 }
转移:
f[a][b] = f[a - 1][0] + f[a - 1][1] + ... + f[a - 1][b]

时间 O(AT) 如果求 f[a][*] 只用一次循环的话
可以用循环数组

杯具:
把i看成j了,足足调了3个小时,注意,是不吃不喝,也没有上厕所,没有听歌,没有看优酷。。
是精神高度集中地浪费了3个小时!
与非主流之脑残相比,有过之而无不及也。

#include <stdio.h>

#define P 1000000

int T, A, S, B, fam[1024], dp[2][1024*128], *cur, *pre;

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


int main()
{
    
int i, j, cnt, end, sum;

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

    scanf(
"%d%d%d%d"&T, &A, &S, &B);
    
for (i = 0; i < A; i++{
        scanf(
"%d"&j);
        fam[j]
++;
    }

    
    
for (i = 0; i <= fam[1]; i++)
        dp[
1][i] = 1;
    end 
= fam[1];

    
for (i = 2; i <= T; i++{
        cur 
= dp[i & 1];
        pre 
= dp[(i+1& 1];
        cur[
0= pre[0];
        end 
+= fam[i];
        
for (j = 1; j <= end; j++{
            cur[j] 
= cur[j - 1+ pre[j];
            
if (j > fam[i])
                cur[j] 
-= pre[j - fam[i] - 1];
            cur[j] 
+= P;
            cur[j] 
%= P;
        }

    }


    sum 
= 0;
    
for (i = S; i <= B; i++{
        sum 
+= cur[i];
        sum 
%= P;
    }


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

    
return 0;
}

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

POJ 3043 Walk the Talk 动态规划+单词树

首先考虑这个子问题:
从地图上的某一点开始一直向右上方发展,一共能组成多少个以这个点的字母为开头的单词。
那么要把以这个点为左下角的矩形中的点全部都考察一遍。
假设这个点的字母为'N',那就要看所有单词组成的单词树里面,所有'N'节点孩子的字母,是否出现在这个矩形中。
如果有出现的话,则又是一个子问题了。
把所有这样的子问题的和求出来,就是答案了。

再考虑一个细节:
'N'节点在单词树中可以出现很多次,因此每个'N'节点都是一个子问题。表示:
所有组成的单词,第一个字母节点是'N',余下的字母节点出现的'N'的子树里。
动态规划的时候,对于每个节点要处理一次,因为每个节点的孩子都不一样。
在矩形中统计所有孩子对应的子问题的和。

关键是怎么存放子问题的答案:
我们需要找出矩形中跟指定孩子对应的点。如果把答案存放在地图W*H的数组里面,那就比较麻烦,需要枚举。
但是如果存放在单词树里面,就好很多。
如果我们从上往下扫描每一行,每一行从右到左扫描。那就只需要存放长度为W的一维数组了。

考虑一个细节:
对于地图上的点'N',要以什么样的顺序处理单词树的每个'N'。
按照单词树的位置,应该从上到下处理。


代码写出来,跑了100ms+,居然排到第9,然后换了gcc编译,又排前了一点!
发现前面的人,除了第二名,估计算法都是一样的。

#include <stdio.h>

#define SIZE 64
#define QUEUE_SIZE 4096

struct tree_node {
    
int end, dp[SIZE];
    
struct tree_node *child[26], *next;
}
;

struct queue_node {
    
int idx;
    
struct tree_node *ptr;
}
;

int H, W;
char map[SIZE][SIZE];
struct tree_node nodes[QUEUE_SIZE], root, *hash[26];
int nodes_cnt;
struct queue_node queue[QUEUE_SIZE];
int tail, head;

inline 
void bfs()
{
    
struct tree_node *t;
    
int i;

    head 
= tail = 0;
    queue[tail
++].ptr = &root;
    
while (head != tail) {
        t 
= queue[head++].ptr;
        
for (i = 0; i < 26; i++{
            
if (!t->child[i])
                
continue;
            queue[tail].ptr 
= t->child[i];
            queue[tail].idx 
= i;
            tail
++;
        }

    }

    
for (tail--; tail >= 1; tail--{
        t 
= queue[tail].ptr;
        i 
= queue[tail].idx;
        t
->next = hash[i];
        hash[i] 
= t;
    }

}


inline 
void calc(int y, int x)
{
    
struct tree_node *t, *c;
    
int i, j, sum;

    
for (t = hash[map[y][x] - 'A']; t; t = t->next) {
        sum 
= t->end;
        
for (i = 0; i < 26; i++{
            c 
= t->child[i];
            
if (!c)
                
continue;
            
for (j = W - 1; j >= x; j--)
                sum 
+= c->dp[j];
        }

        t
->dp[x] += sum;
    }

}


int main()
{
    
int i, j, sum;
    
char str[64], *s;
    
struct tree_node *t, **p;

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

    scanf(
"%d%d"&H, &W);
    
for (i = 0; i < H; i++)
        scanf(
"%s", map[i]);
    
while (scanf("%s", str) != EOF) {
        t 
= &root;
        
for (s = str; *s; s++{
            p 
= &t->child[*- 'A'];
            
if (!*p) 
                
*= &nodes[nodes_cnt++];
            t 
= *p;
        }

        t
->end++;
    }

    bfs();

    
for (i = 0; i < H; i++)
        
for (j = W - 1; j >= 0; j--)
            calc(i, j);

    sum 
= 0;
    
for (i = 0; i < 26; i++{
        t 
= root.child[i];
        
if (!t)
            
continue;
        
for (j = 0; j < W; j++)
            sum 
+= t->dp[j];
    }

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

    
return 0;
}


posted @ 2010-04-09 17:35 糯米 阅读(618) | 评论 (0)编辑 收藏

POJ 2394 Checking an Alibi 阴人题

思路:

就是一个最短路径的问题。但是题目数据规模跟描述不符合。
数组要开大一些才能过。官方数据是描述是符合的,可能是管理员加了一些进去。

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

#define MAX_E 4096
#define MAX_V 2048
#define MAX_COST (1 << 30)

struct edge_node {
    
int idx, cost;
    
struct edge_node *next;
}
;

struct graph_node {
    
struct edge_node edges[MAX_E], *map[MAX_V];
    
int edges_cnt, vertexs_cnt;
    
int min_dis[MAX_V];
}
;

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


inline 
void graph_init(struct graph_node *g, int vertexs_cnt)
{
    g
->vertexs_cnt = vertexs_cnt;
    g
->edges_cnt = 0;
    memset(g
->map, 0, vertexs_cnt * sizeof(g->map[0]));
}


inline 
void graph_addedge(struct graph_node *g, 
                          
int from, int to, 
                          
int cost
                          )
{
    
struct edge_node *e;

    e 
= &g->edges[g->edges_cnt++];
    e
->idx = to;
    e
->cost = cost;
    e
->next = g->map[from];
    g
->map[from] = e;
}



inline 
void graph_spfa(struct graph_node *g, int idx)
{
    
static int queue[MAX_V], vis[MAX_V], tm, head, tail;
    
int i, val;
    
struct edge_node *e;

    
for (i = 0; i < g->vertexs_cnt; i++)
        g
->min_dis[i] = MAX_COST;
    g
->min_dis[idx] = 0;
    
    head 
= tail = 0;
    tm
++;
    queue[tail
++= idx;

    
while (head != tail) {
        idx 
= queue[head++];
        vis[idx] 
= 0;
        
for (e = g->map[idx]; e; e = e->next) {
            val 
= g->min_dis[idx] + e->cost;
            
if (val >= g->min_dis[e->idx])
                
continue;
            g
->min_dis[e->idx] = val;
            
if (vis[e->idx] == tm) 
                
continue;
            queue[tail
++= e->idx;
            vis[e
->idx] = tm;
        }

    }

}


int main()
{
    
static int loc[MAX_V], i, F, C, P, M, from, to, cost, cnt;
    
static struct graph_node g;

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

    scanf(
"%d%d%d%d"&F, &P, &C, &M);
    graph_init(
&g, F + 1);
    
while (P--{
        scanf(
"%d%d%d"&from, &to, &cost);
        graph_addedge(
&g, from, to, cost);
        graph_addedge(
&g, to, from, cost);
    }

    
for (i = 0; i < C; i++)
        scanf(
"%d"&loc[i]);

    graph_spfa(
&g, 1);
    cnt 
= 0;
    
for (i = 0; i < C; i++)
        cnt 
+= (g.min_dis[loc[i]] <= M);
    printf(
"%d\n", cnt);
    
for (i = 0; i < C; i++)
        
if (g.min_dis[loc[i]] <= M)
            printf(
"%d\n", i + 1);

    
return 0;
}

posted @ 2010-04-06 23:42 糯米 阅读(353) | 评论 (1)编辑 收藏

POJ 2135 Farm Tour 最小费用最大流

     摘要: 第一次写这玩意,还真有点麻烦,出了点问题。然后看了一下别人的代码,发现双向边,要分成两个单向边来插入。长见识了。而且费用的值有正有负,最好用SPFA来找最短路径。思路:建立一个超级源点,跟点1连起来,容量为2。建立一个超级汇点,跟点N连起来,容量为2。其他的边容量均为1。#include <stdio.h>#include <stdlib.h>#inc...  阅读全文

posted @ 2010-04-06 23:40 糯米 阅读(761) | 评论 (4)编辑 收藏

POJ 3049 Securing the Barn 水题/搜索

#include <stdio.h>

int L, C;
char path[26], arr[26], map[256];

void dfs(int i, int vowels, int idx)
{
    
if (idx == L) {
        
if (vowels)
            printf(
"%s\n", path);
        
return ;
    }

    
for ( ; i <= C - L + idx; i++{
        path[idx] 
= arr[i];
        dfs(i 
+ 1, vowels + (arr[i] == 'a' || arr[i] == 'e' || 
                             arr[i] 
== 'i' || arr[i] == 'o' || 
                             arr[i] 
== 'u'), 
            idx 
+ 1);
    }

}


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

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

    scanf(
"%d%d"&L, &C);
    
for (i = 0; i < C; i++{
        scanf(
"%s", str);
        map[str[
0]]++;
    }

    j 
= 0;
    
for (i = 'a'; i <= 'z'; i++)
        
if (map[i])
            arr[j
++= i;
    path[L] 
= 0;
    dfs(
000);

    
return 0;
}

posted @ 2010-04-06 23:34 糯米 阅读(344) | 评论 (0)编辑 收藏

POJ 2395 Out of Hay 二分+深搜

思路:

留意到题目里面有一句话“All farms are connected one way or another to Farm 1.”。
这貌似说明图一开始就是连通的。

二分答案,判断依据是:
如果将大于某个长度的边都去掉以后,图就不连通了。
那这个长度相对答案来说,一定是大了。


#include <stdio.h>

#define MAX_M 10032
#define MAX_N 2048

struct edge_node {
    
int idx, len;
    
struct edge_node *next;
}
;

struct edge_node edges[MAX_M*2], *map[MAX_N];
int N, M, vis[MAX_N], tm, stk[MAX_N], *sp;

inline 
int can(int limit)
{
    
int cnt;
    
struct edge_node *e;

    tm
++;
    sp 
= stk;
    
*sp++ = 1;
    vis[
1= tm;
    cnt 
= 0;
    
while (sp > stk) {
        sp
--;
        cnt
++;
        
for (e = map[*sp]; e; e = e->next) {
            
if (vis[e->idx] == tm || e->len > limit) 
                
continue;
            vis[e
->idx] = tm;
            
*sp++ = e->idx;
        }

    }


    
return cnt == N;
}


inline 
void insert(struct edge_node *e, int a, int b, int len)
{
    e
->idx = b;
    e
->len = len;
    e
->next = map[a];
    map[a] 
= e;
}


int main()
{
    
int l, r, m, i, a, b, len;

    scanf(
"%d%d"&N, &M);
    l 
= 0x7fffffff;
    r 
= 0;
    
for (i = 0; i < M*2; i += 2{
        scanf(
"%d%d%d"&a, &b, &len);
        insert(
&edges[i], a, b, len);
        insert(
&edges[i + 1], b, a, len);
        
if (len < l)
            l 
= len;
        
if (len > r)
            r 
= len;
    }


    
while (l <= r) {
        m 
= (l + r) / 2;
        
if (!can(m))
            l 
= m + 1;
        
else
            r 
= m - 1;
    }

    printf(
"%d\n", r + 1);

    
return 0;
}


posted @ 2010-04-06 23:33 糯米 阅读(253) | 评论 (0)编辑 收藏

POJ 2393 Yogurt factory 水题

思路:

每天要么以今天的价格买入,要么前面某天买了存在仓库里。不存在一半是今天买的,一半是从仓库拿的,这种情况。
因为如果这样,肯定有一半具有更高的性价比,那就全部都改成更高性价比的方式就好了。。
所以,这题只需要保存一个当前的最大值,扫描一遍就能出结果了。瞬间就沦为一道水题了。还以为要大动作的呢。

#include <stdio.h>

__int64 N, S;

__inline __int64 min(__int64 a, __int64 b)
{
    
return a < b ? a : b;
}


int main()
{
    __int64 best, i, c, y, sum, inc;

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

    scanf(
"%I64d%I64d"&N, &S);
    best 
= 1LL << 60;
    sum 
= 0;
    inc 
= (N - 1* S;
    
for (i = 0; i < N; i++{
        scanf(
"%I64d%I64d"&c, &y);
        best 
= min(best, c + inc);
        sum 
+= y * (best - inc);
        inc 
-= S;
    }

    printf(
"%I64d\n", sum);

    
return 0;
}

posted @ 2010-04-06 23:22 糯米 阅读(417) | 评论 (0)编辑 收藏

POJ 2230 Watchcow 深搜

思路:

深搜的时候,可以生成一棵树。
深搜也就是深度遍历这棵树,把遍历的路径打印出来,就解决了一部分边了,这部分边都是经过两次的,来一次去一次。
剩下的边,就是遍历的时候正在访问的节点与已经访问的节点之间的边,很容易的判断的。同样把这部分路径也打印出来。
后来看了 Discuss 才发现,这个东西叫做“欧拉回路”,又长见识了。

代码
#include <stdio.h>

#define MAX_M 50032
#define MAX_N 10032

int N, M;

struct edge_node {
    
int vis, to;
    
struct edge_node *next;
}
;
struct edge_node edges[MAX_M * 2], *map[MAX_N];
int edges_cnt, vis[MAX_N];

inline 
void insert(struct edge_node *e, int from, int to)
{
    e
->to = to;
    e
->next = map[from];
    map[from] 
= e;
}


void dfs(int idx)
{
    
struct edge_node *e;
    
int i;

    vis[idx] 
= 1;
    printf(
"%d\n", idx);

    
for (e = map[idx]; e; e = e->next) {
        i 
= e - edges;
        
if (vis[e->to]) {
            
if (e->vis)
                
continue;
            edges[i].vis 
= 1;
            edges[i 
^ 1].vis = 1;
            printf(
"%d\n%d\n", e->to, idx);
            
continue;
        }

        edges[i].vis 
= 1;
        edges[i 
^ 1].vis = 1;
        dfs(e
->to);
        printf(
"%d\n", idx);
    }

}


int main()
{
    
int from, to, i;

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

    scanf(
"%d%d"&N, &M);
    
for (i = 0; i < M*2; i += 2{
        scanf(
"%d%d"&from, &to);
        insert(
&edges[i], from, to);
        insert(
&edges[i + 1], to, from);
    }

    dfs(
1);

    
return 0;
}

posted @ 2010-04-06 22:55 糯米 阅读(368) | 评论 (0)编辑 收藏

POJ 1659 Frogs' Neighborhood 搜索

 

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

int T, N, arr[16], map[16][16];

int dfs(int idx, int i)
{
    
if (idx >= N)
        
return 1;
    
if (!arr[idx])
        
return dfs(idx + 1, idx + 2);
    
for ( ; i < N; i++{
        
if (!arr[i])
            
continue;
        arr[i]
--;
        arr[idx]
--;
        map[idx][i]
++;
        map[i][idx]
++;
        
if (dfs(idx, i + 1))
            
return 1;
        arr[i]
++;
        arr[idx]
++;
        map[idx][i]
--;
        map[i][idx]
--;
    }

    
return 0;
}


int main()
{
    
int i, j;

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

    scanf(
"%d"&T);
    
while (T--{
        scanf(
"%d"&N);
        
for (i = 0; i < N; i++)
            scanf(
"%d"&arr[i]);
        memset(map, 
0sizeof(map));
        
if (dfs(01)) {
            printf(
"YES\n");
            
for (i = 0; i < N; i++{
                
for (j = 0; j < N; j++)
                    printf(
"%d ", map[i][j]);
                printf(
"\n");
            }

            printf(
"\n");
        }
 else 
            printf(
"NO\n\n");
    }


    
return 0;
}

posted @ 2010-04-06 22:44 糯米 阅读(170) | 评论 (0)编辑 收藏

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