A Za, A Za, Fighting...

坚信:勤能补拙

问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=3259

思路:
这题的描述挺有意思,通过某些路径可以回到过去之类,其实就是求是否存在负权回路的问题
Bellman-Ford算法的典型应用
一个问题是,Bellman-Ford用于判断从某个源点可达的负权回路,而这里求的是整个图,而且也没有说明该图一定是connected的
解决上述问题的一个方法就是添加一个顶点,然后从该新顶点到每个其他顶点添加一条权值为0的边

代码:
 1 /* Bellman-Ford algorithm */
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #define MAX_N 501
 6 #define MAX_M 2501
 7 #define MAX_W 201
 8 #define INF 0x7FFFFFFF
 9 struct Edge {
10     int from, to;
11     int cost;
12 } edges[MAX_M*2+MAX_W+MAX_N];
13 int d[MAX_N];
14 int n, total;
15 
16 void
17 init()
18 {
19     int i, m, w, f, t, c;
20     scanf("%d %d %d"&n, &m, &w);
21     total = 0/* the number of edges */
22     for(i=0; i<m; i++) {
23         scanf("%d %d %d"&f, &t, &c);
24         edges[total].from = f;
25         edges[total].to = t;
26         edges[total++].cost = c;
27         edges[total].from = t;
28         edges[total].to = f;
29         edges[total++].cost = c;
30     }
31     for(i=0; i<w; i++) {
32         scanf("%d %d %d"&f, &t, &c);
33         edges[total].from = f;
34         edges[total].to = t;
35         edges[total++].cost = c*(-1);
36     }
37     /* in order to keep connectivity, add one vertex: '0' */
38     for(i=1; i<=n; i++) {
39         edges[total].from = 0;
40         edges[total].to = i;
41         edges[total++].cost = 0;
42     }
43 }
44 
45 void
46 relax(struct Edge *e)
47 {
48     if(d[e->from] == INF)
49         return;
50     if(d[e->to] > d[e->from]+e->cost)
51         d[e->to] = d[e->from]+e->cost;
52 }
53 
54 int
55 bellman_ford()
56 {
57     int i, j;
58     for(i=0; i<=n; i++)
59         d[i] = INF;
60     d[0= 0;
61     for(i=0; i<n; i++)  /* n+1 vertices */
62         for(j=0; j<total; j++)  /* 2*m+w+n edges */
63             relax(edges+j);
64     for(j=0; j<total; j++) {
65         if(d[edges[j].to] > d[edges[j].from]+edges[j].cost)
66             return 0;
67     }
68     return 1;
69 }
70 
71 int
72 main(int argc, char **argv)
73 {
74     int F;
75     scanf("%d"&F);
76     while(F--) {
77         init();
78         printf("%s\n", bellman_ford()==1?"NO":"YES");
79     }
80 }
posted @ 2010-09-07 22:29 simplyzhao 阅读(285) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=2394

思路:
题目说的有点复杂,其实就是求单源最短路径,Dijkstra算法
需要注意的是输入可能有重边
具体关于Dijkstra算法,参考算法导论,有详细的证明
第一次写该算法,一次AC   o(∩_∩)o...哈哈

代码:
 1 /* dijkstra algorithm */
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #define MAX_F 501
 6 #define MAX_C 101
 7 #define INF 0x7FFFFFFF
 8 int adj[MAX_F][MAX_F];
 9 int pos[MAX_C];
10 int in[MAX_F], d[MAX_F];
11 int f, p, c, m;
12 
13 void
14 init()
15 {
16     int i, from, to, cost;
17     memset(adj, 0sizeof(adj));
18     scanf("%d %d %d %d"&f, &p, &c, &m);
19     for(i=0; i<p; i++) {
20         scanf("%d %d %d"&from, &to, &cost);
21         if(adj[from][to]==0 || adj[from][to]>cost)
22             adj[from][to] = adj[to][from] = cost;
23     }
24     for(i=1; i<=c; i++)
25         scanf("%d", pos+i);
26 }
27 
28 void
29 dijkstra()
30 {
31     int i, j, k, cur;
32     memset(in0sizeof(in));
33     for(i=1; i<=f; i++)
34         d[i] = INF;
35     d[1= 0;
36     in[1= 1;
37     for(j=1; j<=f; j++)
38         if(!in[j] && adj[1][j])
39             d[j] = adj[1][j];
40     for(i=2; i<=f; i++) {
41         cur = INF;
42         for(j=1; j<=f; j++)
43             if(!in[j] && d[j]<=cur) {
44                 k = j;
45                 cur = d[j];
46             }
47         in[k] = 1;
48         for(j=1; j<=f; j++)
49             if(!in[j] && adj[k][j] && d[k]!=INF)
50                 if(d[j] > d[k]+adj[k][j])
51                     d[j] = d[k]+adj[k][j];
52     }
53 }
54 
55 void
56 output()
57 {
58     int i, n = 0;
59     for(i=1; i<=c; i++)
60         if(d[pos[i]] <= m) {
61             ++n;
62             pos[i] = -1;
63         }
64     printf("%d\n", n);
65     for(i=1; i<=c; i++)
66         if(pos[i] == -1)
67             printf("%d\n", i);
68 }
69 
70 int
71 main(int argc, char **argv)
72 {
73     init();
74     dijkstra();
75     output();
76 }

posted @ 2010-09-07 20:18 simplyzhao 阅读(172) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1054

思路:
好题,枚举 + 二分
枚举所有可能路径的前两个点
要注意的是: starting outside the paddy on one side and ending outside the paddy on the other side

代码:
 1 /* enumerate the first two points for each possible path */
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #define MAX_NUM 5001
 6 #define is_valid(x, y) ((x)>0 && (x)<=R && (y)>0 && (y)<=C)
 7 int R, C;
 8 int total;
 9 struct Point {
10     int x, y;
11 } points[MAX_NUM];
12 
13 /* from top to down, and left to right */
14 int
15 compare(const void *arg1, const void *arg2)
16 {
17     struct Point *= (struct Point *)arg1;
18     struct Point *= (struct Point *)arg2;
19     if(a->== b->x)
20         return a->- b->y;
21     return a->- b->x;
22 }
23 
24 void
25 init()
26 {
27     int i;
28     scanf("%d"&total);
29     for(i=0; i<total; i++)
30         scanf("%d %d"&points[i].x, &points[i].y);
31     qsort(points, total, sizeof(struct Point), compare);
32 }
33 
34 void
35 solve()
36 {
37     int i, j, tmp, max = 0;
38     int diff_x, diff_y;
39     struct Point p1, p2, next;
40     struct Point *ptr;
41     for(i=0; i<total; i++) {
42         for(j=i+1; j<total; j++) {
43             tmp = 2;
44             p1 = points[i];
45             p2 = points[j];
46             diff_x = p2.x - p1.x;
47             diff_y = p2.y - p1.y;
48             if(is_valid(p1.x-diff_x, p1.y-diff_y)) /* starting outside */
49                 continue;
50             if(!is_valid(p1.x+max*diff_x, p1.y+max*diff_y)) /* pruning */
51                 continue;
52             next.x = p2.x + diff_x;
53             next.y = p2.y + diff_y;
54             while(is_valid(next.x, next.y)) {
55                 if((ptr=(struct Point *)bsearch(&next, points, total, sizeof(struct Point), compare)) == NULL) {
56                     tmp = 0/* ending outside */
57                     break;
58                 }
59                 ++tmp;
60                 next.x += diff_x;
61                 next.y += diff_y;
62             }
63             max = tmp>max ? tmp : max;
64         }
65     }
66     printf("%d\n", max>2 ? max : 0);
67 }
68 
69 int
70 main(int argc, char **argv)
71 {
72     while(scanf("%d %d"&R, &C) != EOF) {
73         init();
74         solve();
75     }
76 }

posted @ 2010-09-07 17:18 simplyzhao 阅读(192) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=2421

思路:
非常类似于PKU 2485   Highways
区别在于: "there are already some roads between some villages"
如何在求最小生成树的算法中体现某些路径已经存在了呢?
对于Prim算法,只要将已经存在的路径(u, v)的权重设置为0即可(为什么?)
对于Kruskal算法,比较容易理解,只要将已经存在的路径(u, v)进行Union操作即可,即将u, v看作是一个连通域
posted @ 2010-09-05 19:58 simplyzhao 阅读(201) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1861
http://acm.pku.edu.cn/JudgeOnline/problem?id=2485

思路:
这里题目并没有明确要求求最小生成树,而是要求一颗最长边最小的生成树
我们可以证明:
       如果T是一颗最小生成树,那么T所包含的最长边一定是所有生成树中最小的,即最小生成树满足题目要求
Prove:
如果T的最长边(x, y)并非最小
那么,存在一颗生成树R,其最长边(u, v)<(x, y),即生成树R的任何一条边都小于(x, y)
现在,采用剪切-粘帖的方法来证明T不是一颗最小生成树,即矛盾
将T中的最长边(x, y)剪切掉,这样就得到两颗子树
在R中,至少存在一条边(p, q)可以将这两颗子树连接起来,这样就得到:
           T - (x, y) + (p, q) < T

代码(这里采用Kruskal算法,并查集实现)
 1 /* union-find sets, Kruskal algorithm */
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #define MAX_N 1001
 6 #define MAX_M 15001
 7 struct Edge{
 8     int len;
 9     int from, to;
10 }edges[MAX_M];
11 int parent[MAX_N], rank[MAX_N];
12 int n, m;
13 
14 void
15 make_set()
16 {
17     int i;
18     for(i=1; i<=n; i++)
19         parent[i] = i;
20     memset(rank, 0sizeof(rank));
21 }
22 
23 int
24 find(int x)
25 {
26     int tmp, rt = x;
27     while(parent[rt] != rt)
28         rt = parent[rt];
29     while(x != rt) {
30         tmp = parent[x];
31         parent[x] = rt;
32         x = tmp;
33     }
34     return rt;
35 }
36 
37 void
38 Union(int x, int y)
39 {
40     int a = find(x);
41     int b = find(y);
42     if(a == b)
43         return;
44     if(rank[a] > rank[b])
45         parent[b] = a;
46     else {
47         parent[a] = b;
48         if(rank[a] == rank[b])
49             ++rank[b];
50     }
51 }
52 
53 int
54 compare(const void *arg1, const void *arg2)
55 {
56     return ((struct Edge *)arg1)->len - ((struct Edge *)arg2)->len;
57 }
58 
59 void
60 init()
61 {
62     int i;
63     for(i=0; i<m; i++
64         scanf("%d %d %d"&edges[i].from, &edges[i].to, &edges[i].len);
65     qsort(edges, m, sizeof(struct Edge), compare);
66 }
67 
68 void
69 kruskal()
70 {
71     int i, a, b, count = 0;
72     int mark[MAX_N];
73     make_set();
74     for(i=0; i<m; i++) {
75         a = find(edges[i].from);
76         b = find(edges[i].to);
77         if(a != b) {
78             mark[count++= i;
79             Union(a, b);
80         }
81     }
82     /* output */
83     printf("%d\n", edges[mark[count-1]].len);
84     printf("%d\n", count);
85     for(i=0; i<count; i++)
86         printf("%d %d\n", edges[mark[i]].from, edges[mark[i]].to);
87 }
88 
89 int
90 main(int argc, char **argv)
91 {
92     while(scanf("%d %d"&n, &m) != EOF) {
93         init();
94         kruskal();
95     }
96 }


posted @ 2010-09-05 13:09 simplyzhao 阅读(179) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1251
http://acm.pku.edu.cn/JudgeOnline/problem?id=1258

思路:
最简单典型的最小生成树,PRIM算法
参考算法导论

代码(pku 1251):
 1 /* MST problem */
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #define MAX_LEN 27
 6 #define INF 0x7FFFFFFF
 7 int num, min;
 8 int adj[MAX_LEN][MAX_LEN];
 9 int key[MAX_LEN], in[MAX_LEN];
10 
11 void
12 init()
13 {
14     int i, j, k, dis;
15     char tmp[2], tmp1[2];
16     memset(adj, 0sizeof(adj));
17     memset(in0sizeof(in));
18     min = 0;
19     for(i=0; i<num; i++)
20         key[i] = INF;
21     for(i=0; i<num-1; i++) {
22         scanf("%s %d", tmp, &k);
23         for(j=0; j<k; j++) {
24             scanf("%s %d", tmp1, &dis);
25             adj[tmp[0]-'A'][tmp1[0]-'A'= dis;
26             adj[tmp1[0]-'A'][tmp[0]-'A'= dis;
27         }
28     }
29 }
30 
31 void
32 prim()
33 {
34     int i, j, k, cur;
35     /* start from vertex 'A' */
36     in[0= 1;
37     for(i=1; i<num; i++)
38         if(adj[0][i])
39             key[i] = adj[0][i];
40     for(i=1; i<num; i++) { /* num-1 vertex left */
41         cur = INF;
42         for(j=0; j<num; j++) {
43             if(!in[j] && key[j]<cur) {
44                 cur = key[j];
45                 k = j;
46             }
47         }
48         min += cur;
49         in[k] = 1;
50         for(j=0; j<num; j++) {
51             if(adj[k][j]) {
52                 if(!in[j] && adj[k][j]<key[j])
53                     key[j] = adj[k][j];
54             }
55         }
56     }
57 }
58 
59 int
60 main(int argc, char **argv)
61 {
62     while(scanf("%d"&num)!=EOF && num) {
63         init();
64         prim();
65         printf("%d\n", min);
66     }
67 }

posted @ 2010-09-05 00:09 simplyzhao 阅读(156) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=3687

思路:
这题理解起来就很困难,等理解透了也还是不会

参考:
http://hi.baidu.com/archersfate/blog/item/30e66f76734a0c12b051b9ab.html

总结:
逆向的拓扑排序,等同于对转置图进行正向的拓扑排序(其实就是入度与出度的区别)
DFS实现拓扑排序适合于求出所有可能的解
BFS实现拓扑排序适合于求出满足特定要求的解


代码:
 1 /* cpp: priority_queue */
 2 #include<iostream>
 3 #include<queue>
 4 #include<vector>
 5 #include<functional>
 6 #include<cstdio>
 7 #include<cstring>
 8 using namespace std;
 9 
10 #define MAX_N 201
11 int n, m;
12 int adj[MAX_N][MAX_N];
13 int out_degree[MAX_N], topo[MAX_N], ans[MAX_N];
14 
15 void
16 init()
17 {
18     int i, pre, suc;
19     memset(adj, 0sizeof(adj));
20     memset(out_degree, 0sizeof(out_degree));
21     scanf("%d %d"&n, &m);
22     for(i=0; i<m; i++) {
23         scanf("%d %d"&pre, &suc);
24         if(!adj[pre][suc]) { /* avoid duplicates */
25             adj[pre][suc] = 1;
26             ++out_degree[pre];
27         }
28     }
29 }
30 
31 void
32 reverse_topo_sort()
33 {
34     int i, tmp, count = 0;
35     priority_queue<int, vector<int>, less<int> > Q;
36     for(i=1; i<=n; i++)
37         if(out_degree[i] == 0)
38             Q.push(i);
39     while(!Q.empty()) { /* BFS */
40         tmp = Q.top();
41         Q.pop();
42         topo[++count] = tmp;
43         for(i=1; i<=n; i++)
44             if(adj[i][tmp]) {
45                 --out_degree[i];
46                 if(!out_degree[i])
47                     Q.push(i);
48             }
49     }
50     if(count != n) { /* not DAG */
51         printf("-1\n");
52         return;
53     }
54     for(i=1; i<=n; i++)
55         ans[topo[n-i+1]] = i;
56     for(i=1; i<=n; i++)
57         printf("%d ", ans[i]);
58     printf("\n");
59 }
60 
61 int
62 main(int argc, char **argv)
63 {
64     int tests;
65     scanf("%d"&tests);
66     while(tests--) {
67         init();
68         reverse_topo_sort();
69     }
70 }

转载:
   PKU 3687 在基本的拓扑排序的基础上又增加了一个要求:编号最小的节点要尽量排在前面;在满足上一个条件的基础上,编号第二小的节点要尽量排在前面;在满足前两个条件的基础上,编号第三小的节点要尽量排在前面……依此类推。(注意,这和字典序是两回事,不可以混淆。)

    如图 1 所示,满足要求的拓扑序应该是:6 4 1 3 9 2 5 7 8 0。



图 1 一个拓扑排序的例子

    一般来说,在一个有向无环图中,用 BFS 进行拓扑排序是比较常见的
做法
做法,如算法 1 所示。但是它不一定能得到本题要求的拓扑序。

1. 把所有入度为 0 的节点放进队列 Q
2. WHILE: Q 不是空队列
3.     从 Q 中取出队列首元素 a,把 a 添加到答案的尾部
4.     FOR:所有从 a 出发的边 a → b
5.         把 b 的入度减 1。如果 b 的入度变为 0,则把 b 放进队列 Q。

算法 1 用 BFS 进行拓扑排序

    为了解决本问题,下面让我来探究一下拓扑序的一些性质。以图 1 为例,节点 0 毫无疑问排在最后。除了节点 0 以外,有三条互相平行的路径:6 → 4 → 1、 3→ 9 → 2 和 5 → 7 → 8。一条路径上的各个节点的先后关系都是不能改变的,比如路径 6 → 4 → 1 上的三个节点在拓扑序中,一定是 6 在最前,1 在最后。但是,互相平行的各条路径,在总的拓扑序中任意交错都是合法的。比如,以下都是图 1 的合法拓扑序:

    6 4 1 3 9 2 5 7 8 0、 3 6 9 4 5 1 7 8 2 0、 5 6 4 7 3 8 1 9 2 0、 3 5 6 4 1 7 9 2 8 0、 6 5 7 8 4 3 9 2 1 0。

    怎么才能找出题目要求的拓扑序呢?在这里,我想用字典序最先的拓扑序来引出这个算法。算法 2 可以求出字典序最先的拓扑序。

1. 把所有入度为 0 的节点放进优先队列 PQ
2. WHILE: PQ 不是空队列
3. 从 PQ 中取出编号最小的元素 a,把 a 添加到答案的尾部
4. FOR:所有从 a 出发的边 a → b
5. 把 b 的入度减 1。如果 b 的入度变为 0,则把 b 放进优先队列 PQ。

算法 2 求出字典序最先的拓扑序

    可见,算法 2 和算法 1 基本一样,只是把队列改成了优先队列。用它求出的图 1 的字典序最先的拓扑序为:3 5 6 4 1 7 8 9 2 0。但是这显然不是本题要求的答案,因为节点 1 的位置还不够靠前。

    算法 2 可以算是一个贪心算法,每一步都找编号最小的节点。但是对于图 1 中的三条路径,头的编号比较小的,不一定要先出队列。正确的步骤应该如下:
  1. 节点 0 的位置是铁定在最后的,不用考虑。只考虑剩下的三条路径。
  2. 先找编号最小的,节点 1。把它和它所在的路径中位于它前面的节点全部拿出来。目前的答案是 6 4 1,这样, 节点 1 就尽量靠前了。
  3. 再找剩下的节点中编号最小的,节点 2。把它和它所在的路径中位于它前面的节点全部拿出来。目前的答案是 6 4 1 3 9 2 ,这样,节点 2 就尽量靠前了。
  4. 只剩下一条路径了,只能依次把其中的节点拿出来。最后答案就是 6 4 1 3 9 2 5 7 8 0。
    显然,算法 2 的贪心策略对于这个问题是不可行的。不能着眼于每条路径的头,而是要找编号最小的节点在哪条路径上,优先把这条路径拿出来。但问题在于,在 BFS 的过程中,我们只能看到每条路径的头,看不到后面的节点,这该怎么办呢?

    让我们换个角度想一想,节点 3 和 6,应该是 6 先出队列,因为节点 1 在 6 的后面。这和节点 3 和 6 的编号大小没有任何关系。但是,再看另外两条路径的尾部,节点 2 和 8,可以肯定地说,2 一定先出队列,因为它们后面都没有别的节点了,这个时候完全以这两个节点本身的编号大小决定顺序。归纳起来就是说,对于若干条平行的路径,小的头部不一定排在前面,但是大的尾部一定排在后面。于是,就有了算法 3

1. 把所有出度为 0 的节点放进优先队列 PQ
2. WHILE: PQ 不是空队列
3. 从 PQ 中取出编号最大的元素 a,把 a 添加到答案的头部
4.     FOR:所有指向 a 的边 b → a
5.     把 b 的出度减 1。如果 b 的出度变为 0,则把 b 放进优先队列 PQ。

算法 3 求出本题目要求的拓扑序

    我觉得这道题目确实挺奥妙的,我搞了很久才想通算法 3 为什么是正确的,特地在此写一下。
posted @ 2010-09-04 11:35 simplyzhao 阅读(277) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1664

思路:
就是根据题意进行DFS,要注意的是如何避免重复: 所放苹果数目递减
居然一会就AC了哈哈,暑假的锻炼还是有些成果的:)

代码:
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 int n, m;
 5 int total;
 6 
 7 void
 8 dfs(int level, int left, int last)
 9 {
10     int i, up;
11     if(level==n) {
12         if(left == 0)
13             ++total;
14         return;
15     }
16     up = left<last ? left : last;
17     for(i=up; i>=0; i--)
18         dfs(level+1, left-i, i);
19 }
20 
21 int
22 main(int argc, char **argv)
23 {
24     int tests;
25     scanf("%d"&tests);
26     while(tests--) {
27         scanf("%d %d"&m, &n);
28         total = 0;
29         dfs(0, m, m);
30         printf("%d\n", total);
31     }
32 }
posted @ 2010-09-03 22:48 simplyzhao 阅读(262) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1128

思路:
想法是有:先找出没有被任何其他frame覆盖的frame,然后将该frame进行标记,使之匹配任何字母,然后重复以上过程
不过,程序不知道该如何写

参考discuss以及其他人思路,发现可以用拓扑排序来做(拓扑排序,参考算法导论)
如何根据输入来建立邻接矩阵比较有意思,另外根据各个顶点的入度DFS实现拓扑排序

代码:
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #define MAX_LEN 31
  5 #define MAX_NUM 27
  6 char map[MAX_LEN][MAX_LEN];
  7 int n, m;
  8 int adj[MAX_NUM][MAX_NUM], num, in[MAX_NUM], visited[MAX_NUM];
  9 int x1, y1, x2, y2;
 10 
 11 void
 12 search(char ch)
 13 {
 14     int i, j;
 15     x1 = y1 = MAX_LEN;
 16     x2 = y2 = -1;
 17     for(i=0; i<n; i++)
 18         for(j=0; j<m; j++)
 19             if(map[i][j] == ch) {
 20                 if(i<x1) x1 = i;
 21                 if(i>x2) x2 = i;
 22                 if(j<y1) y1 = j;
 23                 if(j>y2) y2 = j;
 24             }
 25 }
 26 
 27 void
 28 build_graph()
 29 {
 30     int i, j, k;
 31     char ch;
 32     num = 0;
 33     memset(adj, 0sizeof(adj));
 34     memset(in-1sizeof(in));
 35     for(i=0; i<n; i++) {
 36         for(j=0; j<m; j++) {
 37             if(map[i][j]=='.' || in[map[i][j]-'A']>-1)
 38                 continue;
 39             in[map[i][j]-'A'= 0;
 40             ++num;
 41             search(map[i][j]);
 42             for(k=x1; k<=x2; k++) {
 43                 ch = map[k][y1];
 44                 if(ch != map[i][j])
 45                     adj[map[i][j]-'A'][ch-'A'= 1;
 46             }
 47             for(k=x1; k<=x2; k++) {
 48                 ch = map[k][y2];
 49                 if(ch != map[i][j])
 50                     adj[map[i][j]-'A'][ch-'A'= 1;
 51             }
 52             for(k=y1; k<=y2; k++) {
 53                 ch = map[x1][k];
 54                 if(ch != map[i][j])
 55                     adj[map[i][j]-'A'][ch-'A'= 1;
 56             }
 57             for(k=y1; k<=y2; k++) {
 58                 ch = map[x2][k];
 59                 if(ch != map[i][j])
 60                     adj[map[i][j]-'A'][ch-'A'= 1;
 61             }
 62         }
 63     }
 64     for(i=0; i<MAX_NUM; i++)
 65         for(j=0; j<MAX_NUM; j++)
 66             if(adj[i][j])
 67                 ++in[j]; /* in-degree */
 68 }
 69 
 70 void
 71 topological_sort(char *str, int level)
 72 {
 73     int i, j;
 74     if(level == num) {
 75         printf("%s\n", str);
 76         return;
 77     }
 78     for(i=0; i<MAX_NUM; i++) {
 79         if(in[i]==0 && !visited[i]) {
 80             str[level] = 'A'+i;
 81             visited[i] = 1;
 82             for(j=0; j<MAX_NUM; j++)
 83                 if(adj[i][j])
 84                     --in[j];
 85             topological_sort(str, level+1);
 86             visited[i] = 0;
 87             for(j=0; j<MAX_NUM; j++)
 88                 if(adj[i][j])
 89                     ++in[j];
 90         }
 91     }
 92 }
 93 
 94 int
 95 main(int argc, char **argv)
 96 {
 97     int i;
 98     char str[MAX_NUM];
 99     while(scanf("%d %d"&n, &m)!=EOF) {
100         for(i=0; i<n; i++)
101             scanf("%s", map[i]);
102         build_graph();
103         memset(str, 0sizeof(str));
104         memset(visited, 0sizeof(visited));
105         topological_sort(str, 0);
106     }
107 }
posted @ 2010-09-03 16:42 simplyzhao 阅读(261) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1324

参考:
http://hi.baidu.com/aekdycoin/blog/item/08774afbd1a29316a8d31111.html
http://clover520.blogbus.com/logs/38001465.html

思路:
用BFS求最短路径肯定是没有问题的,关键是状态如何表示
参考别人的思路,原来蛇身只需要通过上、下、左、右四个方向表示即可(两bits或4进制),这样可以很大程度上减少空间,而且判重也就不再是个问题,只需要用三维数组表示即可
不过我自己写出来的代码却总是MLE,悲剧...(无奈,贴了别人代码过的,无耻啊)

代码:
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 
 5 int kk[4][2]={1,0,0,1,0,-1,-1,0},N,M,L;
 6 struct point{
 7     char x,y;
 8     int dis,body;
 9 };
10 int bfs();
11 int main(){
12     int Cas=0;
13     while(scanf("%d%d%d",&N,&M,&L)==3){
14         if(N==0&&M==0&&L==0)break;
15         printf("Case %d: %d\n",++Cas,bfs());
16     }
17     return 0;
18 }
19 char viss[20][20][1<<14];
20 int vis(struct point* t){
21     int ans=0,i=0;
22     if(viss[t->x][t->y][t->body])return 1;
23     viss[t->x][t->y][t->body]=1;
24     return 0;
25 }
26 char map[20][20],mapt[20][20];
27 char valid(int x,int y){
28     if(x<0||x>=N||y<0||y>=M||mapt[x][y])return 0;
29     return 1;
30 }
31 struct point Q[20*20*(1<<14)];
32 int head,tail;
33 int bfs(){
34     int x,y,lx,ly,i,k,nx,ny;
35     struct point t,now;
36     memset(viss,0,sizeof(viss));
37     scanf("%d%d",&lx,&ly);
38     t.x=lx-1;t.y=ly-1;t.dis=0;t.body=0;
39     for(i=1;i<L;++i){
40         scanf("%d%d",&x,&y);
41         for(k=0;k<4;++k)if(lx+kk[k][0]==x&&ly+kk[k][1]==y)break;
42         t.body|=k<<((i-1)<<1);
43         lx=x;ly=y;
44     }
45     memset(map,0,sizeof(map));
46     scanf("%d",&k);
47     for(i=0;i<k;++i){
48         scanf("%d%d",&x,&y);
49         map[x-1][y-1]=1;
50     }
51     head=tail=0;
52     Q[tail++]=t;
53     vis(&t);
54     while(head!=tail){
55         now=Q[head++];
56         if(now.x==0&&now.y==0)return now.dis;
57         
58         memcpy(mapt,map,sizeof(map));
59         mapt[x=now.x][y=now.y]=1;
60         int s=now.body;
61         for(i=1;i<L;++i,s>>=2){
62             k=s&3;
63             mapt[x=x+kk[k][0]][y=y+kk[k][1]]=1;
64         }
65         
66         for(k=0;k<4;++k){
67             if(!valid(nx=now.x+kk[k][0],ny=now.y+kk[k][1]))continue;
68             t.x=nx,t.y=ny;
69             t.body=((now.body<<2)|(3-k))&((1<<((L-1)<<1))-1);
70             t.dis=now.dis+1;
71             if(!vis(&t)){
72                 Q[tail++]=t;
73             }
74         }
75     }
76     return -1;
77 }
posted @ 2010-09-03 10:05 simplyzhao 阅读(310) | 评论 (0)编辑 收藏
仅列出标题
共21页: First 9 10 11 12 13 14 15 16 17 Last 

导航

<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜