[topic] 情報オリンピック2007年度国内本選問題4

中高生向けの情報オリンピック国内本選2007年度問題4です。

問題文(下記PDFの8ページ目)
http://www.ioi-jp.org/joi/2007/2008-ho-prob_and_sol/2008-ho.pdf
コンテスト概要
http://www.ioi-jp.org/joi/2007/2008-ho-prob_and_sol/index.html
サンプルデータ(出題時に公開)
http://www.ioi-jp.org/joi/2007/2008-ho-prob_and_sol/joi2008.zip
採点データ(出題時に非公開)
http://www.ioi-jp.org/joi/2007/2008-ho-prob_and_sol/data.zip

「問題ごとに、プログラムの実行時間(や使用メモリ量)に制限が設定されています。」にご注意ください。本問では、制限時間1秒、メモリ制限64MBとなっています。

出題時はサンプルデータのみが公開され、採点は、採点データによる、自動採点にて行われます。

実際のコンテストでは、予選通過者48名が対象となっていて、100点満点中38点以上とった、16名が本選通過です。

Posted feedbacks - Nested

Flatten Hidden
ブログのほうでリクエストがありましたので書き込ませていただきます。
公式ジャッジデータで時間内に正答することは一応確認しています。
少しでも参考になれば幸いです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include<iostream>
#include<vector>

using namespace std; 

#define DEBUG(c) cerr<<"> "<<#c<<" = "<<c<<endl; 

#define R 150
#define S 10

vector<vector<pair<int,int> > > st;

int w(int r,int s,int rr,int i)
{
    return (st[r][s].second+st[rr][i].second)*(abs(st[r][s].first-st[rr][i].first));
}

int min(int a,int b)
{
    if(std::min(a,b)==-1)
        return std::max(a,b);
    
    return std::min(a,b);
}

int main()
{
    
    int n,m; cin>>n>>m;
    
    st.resize(n);
    for(int i=0;i<n;i++)
    {
        int k; cin>>k;
        for(int j=0;j<k;j++)
        {
            int x,d; cin>>x>>d;
            st[i].push_back(make_pair(x,d));
        }
    }
    
    int dp[R][S],dp2[R][S];
    memset(dp,-1,sizeof(int)*R*S);
    
    for(int step=0;step<=m;step++)
    {
        memcpy(dp2,dp,sizeof(int)*R*S);
        for(int r=0;r<n;r++)
        {
            for(int s=0;s<st[r].size();s++)
            {
                if(r==0)
                    dp[r][s]=0;
                else
                {
                    for(int i=0;i<st[r-1].size();i++)
                        if(dp[r-1][i]!=-1)
                            dp[r][s]=min(dp[r][s],dp[r-1][i]+w(r,s,r-1,i));
                }
                
                if(step==0 || r==0)
                    continue;
                
                if(r==1)
                    dp[r][s]=0;
                else
                {
                    for(int i=0;i<st[r-2].size();i++)
                        if(dp2[r-2][i]!=-1)
                            dp[r][s]=min(dp[r][s],dp2[r-2][i]+w(r,s,r-2,i));
                }
            }
        }
    }
    
    //もうゴール、してもいいよね…
    int res=-1;
    for(int i=0;i<S;i++)
        res=min(res,min(dp[n-1][i],dp2[n-2][i]));
    
    cout<<res<<endl;
    
    return 0;
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <limits>
#include <cassert>

#define REP(i, b, e) for (size_t i = b; i < e; ++i)
#define REPE(i, b, e) for (size_t i = b; i <= e; ++i)

void fill(std::vector<long>& v, long value)
{
    std::fill(v.begin(), v.end(), value);
}

int main()
{
    const size_t max_x = 1000;

    std::string s;

    std::getline(std::cin, s);

    size_t n, m;

    std::istringstream(s) >> n >> m;

    assert(2 <= n && n <= 150);

    assert(m <= (n + 1) / 2);

    std::vector<std::vector<long> > slip(n + 3, std::vector<long>(max_x, -1)); // -1 means there is no stone

    fill(slip[0], 0); // start shore (0 is dummy value)

    fill(slip[n + 1], 0); // goal shore (0 is dummy value)

    fill(slip[n + 2], 0); // goal shore (0 is dummy value)

    REPE(y, 1, n)
    {
        std::getline(std::cin, s);

        std::istringstream sin(s);

        size_t k;

        sin >> k;

        assert(k <= 10);

        for (; k; --k)
        {
            size_t x;

            long d;

            sin >> x >> d;

            assert(1 <= x && x <= max_x);

            assert(1 <= d && d <= 1000);

            --x; // now starts with 0 not 1

            slip[y][x] = d;
        }
    }

    std::vector<std::vector<std::vector<long> > > dp(n + 3,
        std::vector<std::vector<long> >(max_x,
            std::vector<long>(m + 1, std::numeric_limits<long>::max())));

    dp.front().swap(
        std::vector<std::vector<long> >(max_x,
            std::vector<long>(m + 1, 0)));

    REPE(y1, 0, n) REP(x1, 0, max_x) if (slip[y1][x1] >= 0) // source
    {
        REPE(y2, y1 + 1, y1 + 2) REP(x2, 0, max_x) if (slip[y2][x2] >= 0) // destinition
        {
            const size_t now_jumped = y2 - y1 - 1;

            assert(now_jumped == 0 || now_jumped == 1);

            for (size_t old_jumped = 0; old_jumped + now_jumped <= m; ++old_jumped)
            {
                if (dp[y1][x1][old_jumped] != std::numeric_limits<long>::max())
                {
                    long& src = dp[y1][x1][old_jumped];

                    long& dst = dp[y2][x2][old_jumped + now_jumped];

                    dst = std::min(dst, src + (slip[y1][x1] + slip[y2][x2]) * long(x2 > x1 ? x2 - x1 : x1 - x2));
                }
            }
        }
    }

    long result = std::numeric_limits<long>::max();

    REPE(y, n + 1, n + 2) REP(x, 0, max_x) REPE(jumped, 0, m) // goal shore
    {
        result = std::min(result, dp[y][x][jumped]);
    }

    std::cout << result << std::endl;
}

g++でコンパイルが通らなかったので、修正。(理由は不明)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
--- 4.cpp.old    Thu May 22 16:17:00 2008
+++ 4.cpp.new    Thu May 22 16:16:47 2008
@@ -72,9 +72,7 @@
         std::vector<std::vector<long> >(max_x,
             std::vector<long>(m + 1, std::numeric_limits<long>::max())));
 
-    dp.front().swap(
-        std::vector<std::vector<long> >(max_x,
-            std::vector<long>(m + 1, 0)));
+    dp[0] = std::vector<std::vector<long> >(max_x, std::vector<long>(m + 1, 0));
 
     REPE(y1, 0, n) REP(x1, 0, max_x) if (slip[y1][x1] >= 0) // source
     {
cppリファレンスによるとswap は
void swap( vector &from );となっているので
一時変数の参照型がまずいのではないでしょうか?

gfilt にかけても↓のような感じに出てくるので
たぶんそこを直せば何とかなるのでは?

gfilt -Wall 6316.cpp
BD Software STL Message Decryptor v3.10 for gcc 2/3/4
6316.cpp: In function `int main()':
6316.cpp:76: error: No match for
   `vector<vector<long int> >::swap(vector<vector<long int>>)'
stl_vector.h:688: candidates are: void vector<
        vector<long int> >::swap(vector<vector<long int> > &)

情報ありがとうございます。こっちならうまくいきました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
--- 4.cpp.new    Fri May 23 15:31:57 2008
+++ 4.cpp.new2    Fri May 23 15:32:13 2008
@@ -72,7 +72,8 @@
         std::vector<std::vector<long> >(max_x,
             std::vector<long>(m + 1, std::numeric_limits<long>::max())));
 
-    dp[0] = std::vector<std::vector<long> >(max_x, std::vector<long>(m + 1, 0));
+    std::vector<std::vector<long> >(max_x,
+        std::vector<long>(m + 1, 0)).swap(dp.front());
 
     REPE(y1, 0, n) REP(x1, 0, max_x) if (slip[y1][x1] >= 0) // source
     {

いっそ、こっちの方が読みやすいかも

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
--- 4.cpp.new    Fri May 23 15:31:57 2008
+++ 4.cpp    Fri May 23 15:41:55 2008
@@ -9,9 +9,9 @@
 #define REP(i, b, e) for (size_t i = b; i < e; ++i)
 #define REPE(i, b, e) for (size_t i = b; i <= e; ++i)
 
-void fill(std::vector<long>& v, long value)
+void zero_fill(std::vector<long>& v)
 {
-    std::fill(v.begin(), v.end(), value);
+    std::fill(v.begin(), v.end(), 0);
 }
 
 int main()
@@ -32,11 +32,11 @@
 
     std::vector<std::vector<long> > slip(n + 3, std::vector<long>(max_x, -1)); // -1 means there is no stone
 
-    fill(slip[0], 0); // start shore (0 is dummy value)
+    zero_fill(slip[0]); // start shore (0 is dummy value)
 
-    fill(slip[n + 1], 0); // goal shore (0 is dummy value)
+    zero_fill(slip[n + 1]); // goal shore (0 is dummy value)
 
-    fill(slip[n + 2], 0); // goal shore (0 is dummy value)
+    zero_fill(slip[n + 2]); // goal shore (0 is dummy value)
 
     REPE(y, 1, n)
     {
@@ -72,7 +72,7 @@
         std::vector<std::vector<long> >(max_x,
             std::vector<long>(m + 1, std::numeric_limits<long>::max())));
 
-    dp[0] = std::vector<std::vector<long> >(max_x, std::vector<long>(m + 1, 0));
+    std::for_each(dp.front().begin(), dp.front().end(), zero_fill);
 
     REPE(y1, 0, n) REP(x1, 0, max_x) if (slip[y1][x1] >= 0) // source
     {

Index

Feed

Other

Link

Pathtraq

loading...