【NOI2006】 聪明的导游

题目描述
 1 聪明的导游
 2 【问题描述】
 3 小佳最近迷上了导游这个工作,一天到晚想着带游客参观各处的景点。正好
 4 M 市在举行 NOI,来参观的人特别的多。不少朋友给小佳介绍了需要导游的人。
 5 M 市有 n 个著名的景点,小佳将这些景点从 1 至 n 编号。有一些景点之间存
 6 在双向的路。小佳可以让游客们在任何一个景点集合,然后带着他们参观,最后
 7 也可以在任何一个景点结束参观。不过,来参观的游客们都不愿去已经参观过的
 8 地方。所以,小佳不能带游客们经过同一个景点两次或两次以上。
 9 小佳希望你帮助他设计一个方案, 走可行的路线, 带游客们参观尽可能多的
10 地方。
11 【输入格式】
12 输入文件为 guide1.in~guide10.in,第一行为两个整数 n,m,分别表示景点数
13 和路的条数。接下来 m 行,每行两个整数 a,b,表示景点 a 和景点 b 之间有一条
14 双向路。
15 【输出格式】
16 你需要将答案输出到 guide1.out~guide10.out 中,guide?.out 为对应 guide?.in
17 的答案。输出的第一行为 p,表示你能找到的路径所经过的景点个数。接下来 p
18 行,每行一个整数,按顺序表示你所找到的路径上的每一个景点。
19 【说明】
20 这是一道提交答案式的题目,你不需要提供任何源代码,只需要将自己的输
21 出文件放在与*.in 同一个目录即可。
22 【样例】
23 样例输入
24 5 5
25 1 2
26 3 2
27 2 4
28 2 5
29 4 5
30 样例输出
31 4
32 1
33 2
34 4
35 5
36 【样例说明】
37 题目可能有多解,该样例有 4 个解,你只需输出其中任何一个解。
38 14 1 2 4 5
39 24 1 2 5 4
40 34 3 2 4 5
41 44 3 2 5 4
42 
43 【评分方法】
44 你的评分将由你的答案与标准答案之间的差异来给定。设你的答案正确且参
45 观的景点数为 x,我们所给出的结果为 ans,则按下表计算你的得分:
46 得分 条件
47 12 x > ans
48 5 x ≥ ans * 0.93
49 10 x = ans
50 4 x ≥ ans * 0.9
51 9 x ≥ ans – 1
52 3 x ≥ ans * 0.8
53 8 x ≥ ans – 2
54 2 x ≥ ans * 0.7
55 7 x ≥ ans – 3
56 1 x ≥ ans * 0.5
57 6 x ≥ ans * 0.95
58 0 x < ans * 0.5
59 如果有多项满足,则取满足条件中的最高得分。

 

题解

 

随机化搜索(去掉random:爆搜)(76分)
 1 (*
 2     *Problem:    NOI2006 聪明的导游
 3     *Author :    Chen Yang
 4     *Time   :    2012.5.31 3:00 am
 5     *State  :    76分
 6     *Memo   :    随机化搜索
 7 *)
 8 program guide;
 9 const x='4';
10 type
11   ty1=^ty2;
12   ty2=record
13     x:longint;
14     next:ty1;
15   end;
16 var
17   n,m,i,sx,sy,step,t,time:longint;
18   first:array[0..10000] of ty1;
19   a:array[0..10000] of longint;
20   get:array[0..10000] of boolean;
21 //========================
22 procedure insert(x,y:longint);
23 var
24   p:ty1;
25 begin
26   new(p);
27   p^.x:=y;
28   p^.next:=first[x];
29   first[x]:=p;
30 end;
31 //========================
32 procedure outit;
33 var
34   i:longint;
35 begin
36   assign(output,'guide'+x+'.out'); rewrite(output);
37   writeln(step);
38   for i:=1 to step do writeln(a[i]);
39   close(output);
40 end;
41 //========================
42 procedure find(x,s:longint);
43 var
44   p:ty1;
45 begin
46   a[s]:=x; get[x]:=true;
47   p:=first[x];
48   while p<>nil do
49   begin
50     if not get[p^.x] then
51     begin
52       //inc(time);
53       //if time>1000000000 then exit;
54       find(p^.x,s+1);
55     end;
56     p:=p^.next;
57   end;
58   if s>step then
59   begin
60     step:=s;
61     outit;
62   end;
63   get[x]:=false;
64 end;
65 //========================
66 begin
67   randomize;
68   assign(input,'guide'+x+'.in'); reset(input);
69   read(n,m);
70   for i:=1 to m do
71   begin
72     read(sx,sy);
73     insert(sx,sy); insert(sy,sx);
74   end;
75   close(input);
76   for i:=n downto 1 do
77   begin
78     t:=random(n)+1; time:=0;
79     find(t,1);
80   end;
81 end.

 

第7个数据的构造(加上上面一共84分)
 1 //for case 7
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <string>
 5 using namespace std;
 6 int n, m;
 7 bool get[10001], g[1001][1001];
 8 
 9 int main()
10 {
11     freopen("guide7.in", "r", stdin);
12     freopen("guide7.out", "w", stdout);
13     scanf("%d%d", &n, &m);
14     printf("%d\n", n);
15     for (int i=1, x, y; i<m+1; ++i) scanf("%d%d", &x, &y), g[x][y] = g[y][x] = 1; 
16     for (int i=1; i<n; i+=5)
17     {
18         int p = 0, q = 0;
19         for (int j=i; j<i+5; ++j)
20         for (int k=i+5; k<i+10; ++k) 
21             if (g[j][k]) p = j, q = k;
22         for (int j=i; j<i+5; ++j)
23             if (!get[j] && j!=p) get[j] = 1, printf("%d\n", j);
24         if (i<n-5) printf("%d\n%d\n", p, q); else printf("%d\n", p);
25         get[p] = get[q] =1;
26     }
27     return 0;
28 }

 

基于树结构的随机化贪心(Solved)
 1 /*
 2     Problem:    NOI2007 聪明的导游
 3     Author :    Chen Yang
 4     Time   :    2012.6.4 8:00 pm
 5     State  :    Solved
 6     Memo   :    利用树结构的随机化贪心
 7 */
 8 #include <cstdio>
 9 #include <cstdlib>
10 #include <cstring>
11 #include <ctime>
12 #include <string>
13 #include <algorithm>
14 using namespace std;
15 const int maxn = 1001, T = 1000;
16 bool get[maxn], g[maxn][maxn];
17 int n, m, best, s, t, a[maxn], len, d1[maxn], d2[maxn]; 
18 struct edge
19 {
20     int x; edge *next; edge() {}
21     edge(int x, edge *next): x(x), next(next) {}
22 } *first[maxn];
23 
24 void outit()
25 {
26     freopen("guide3.out", "w", stdout);
27     printf("%d\n", best);
28     for (int i=1; i<best+1; ++i) printf("%d\n", a[i]);
29     fclose(stdout);
30 }
31 
32 void built(int x, int s)
33 {
34     get[x] = 1;
35     if (len<s) len = s, t = x;
36     for (edge *p=first[x]; p; p=p->next) --d2[p->x];
37     int q=0, k=10000;
38     for (edge *p=first[x]; p; p=p->next)
39     if (!get[p->x])
40     {
41         if (d2[p->x]<k) k=d2[p->x], q=p->x;
42         else if (d2[p->x]==k && (random()&1)) q=p->x;  
43     }
44     if (q) built(q, s+1), g[x][q]=g[q][x]=1;
45     for (edge *p=first[x]; p; p=p->next)
46     if (!get[p->x]) built(p->x, s+1), g[x][p->x]=g[p->x][x]=1;
47 }
48 
49 void find(int x, int fa, int s)
50 {
51     a[s] = x; if (len<s) len=s;
52     for (edge *p=first[x]; p; p=p->next)
53     if (g[x][p->x] && p->x!=fa) find(p->x, x, s+1);
54     if (s>best) best = s, outit();
55 }
56 
57 int main()
58 {
59     srand(time(0));
60     freopen("guide3.in", "r", stdin);
61     scanf("%d%d", &n, &m);
62     for (int i=1; i<=m; ++i)
63     {
64         int x, y;
65         scanf("%d%d", &x, &y);
66         first[x] = new edge(y,first[x]);
67         first[y] = new edge(x,first[y]);
68         d1[x]++, d1[y]++;
69     }
70     for (int i=1; i<T; ++i)
71     {
72         s = rand()%n+1, len = 0;
73         memset(get, 0, sizeof get);
74         memset(g, 0, sizeof g);
75         memcpy(d2, d1, sizeof d1);
76         built(s, 1); 
77         s = len;
78         len = 0;
79         memcpy(d2, d1, sizeof d1);
80         find(t, 0, 1);
81     }
82     return 0;
83 }

 

posted @ 2012-06-03 19:18  datam  阅读(488)  评论(0编辑  收藏  举报