灰太狼抓羊

来源:互联网 发布:淘宝跑包 编辑:程序博客网 时间:2024/06/03 23:50

题目详情:

    羊村新建了许多地下房子,这些地下房子的分布成树状结构。每一个房子有一个编号,从0—n-1,0号是村长的房子。注意每间房子只住着一只羊。

村长的房子是其他所有房子的入口(即根节点),之后每个房子最多通向其他两个房子。房子与房子之间有不同的距离。

  灰太狼听从他老婆的命令,去抓羊。灰太狼总是每秒前行1米,这导致他有时候不能完成他老婆给他的任务。他老婆会有很多次命令,即给他不同的时间(从它的住处出发,抓完羊后再回到住处的总时间)和要抓的羊的数量,你的任务是判断灰太狼能不能完成任务。

  注意:由于抓狼行动在夜晚,所有的羊都睡着了,所以只要灰太狼进入到羊的房间就一定会抓住羊。

输入描述:

  第一行给出三个整数n(1<n<=500),q(0<q<=100000),d,分别表示羊村的房间数目,灰太狼的任务数,灰太狼的住处到羊村的距离(m)。

  接下来n-1行,每行输入三个整数a,b,c,表示房间a到房间b的距离是c米。

  接着是q行,每行两个整数t,m,分别表示t秒,m(m>0)只羊,即灰太狼的老婆给他的任务。

  有多组测试数据当n=0时输入结束。

输出描述:

输出q行。对于每个任务,如果灰太狼有可能完成就输出“I love you”,否则输出“Go to the hell”。



答题说明:

样例输入:

8 8 1

0 1 4

0 2 5

1 3 7

1 4 2

4 6 3

4 7 1

2 5 9

10 2

13 3

22 5

62 8

65 8

0 1

46 7

32 6

0

样例输出:

I love you

Go to the hell

I love you

Go to the hell

I love you

Go to the hell

I love you

I love you

这个题我第一眼看时没什么头绪,那是它刚出出来时了,今天它跑到题目列表的前面去了,我又看了一下,联想到DP上去了,于是就会了,神奇的DP。

首先把一颗子树看成一个子解,也就是从这颗子树内选出来一条关于选取节点数量n的最小路径。于是对于某根节点,其选取过程就只依赖于它的两个子节点了。有dp[x][n] = min(dp[x.leftchild][i] + dp[x.rightchild][n - i])(0 <= i <= n)

这样这个题目就有眉目了。不过接下来才是这次做题的艰难时刻……自己在思维方面还是比较欠缺,花了两个多小时才把代码打出来。对于子树终止条件一直没捋清楚,导致各种BUG。这些都显现出我思路还是不够敏锐……这个要怎么提升啊!

#include<stdio.h>#include<string.h>#define N 550#define INF 0x0fffffffint n, q, d;//连接矩阵 int map[N][N];//足迹 int mark[N];//子树表 int next[N][2];//从父节点到本节点的消耗 int vs[N];int dp[N][N];//递归建立从属关系 void build(int root){int i, j;mark[root] = 1;for(i = j = 0; i < n && j < 2; i++){if(map[root][i] >= 0 && mark[i] == 0){next[root][j] = i;vs[i] = map[root][i];build(i);j++;}}}//建立dp表 void run(int root){int i, j, c1, c2;if(root < 0){//叶子的子节点,当递归run时,会走到这里 return;}c1 = next[root][0], c2 = next[root][1];//两子节点 run(c1);//先建立子dp表 run(c2);dp[root][1] = vs[root] * 2;//仅取根节点 if(c1 > 0 && c2 > 0){//双子都在 for(i = 1; i + 1 <= n; i++){int min = INF;for(j = 0; j <= i; j++){int v1 = c1 > 0 ? dp[c1][j] : INF;//INF表示不可选 int v2 = c2 > 0 ? dp[c2][i - j] : INF;if(v1 + v2 < min){min = v1 + v2;}}dp[root][i + 1] = min + vs[root] * 2;}} else if(c1 > 0){for(i = 1; i + 1 <= n; i++){dp[root][i + 1] = dp[c1][i] + vs[root] * 2;}} else if(c2 > 0){for(i = 1; i + 1 <= n; i++){dp[root][i + 1] = dp[c2][i] + vs[root] * 2;}}}int main(void){int i, j;while(scanf("%d%d%d", &n, &q, &d), n != 0){//初始化 memset(mark, 0, sizeof(mark));for(i = 0; i < N; i++){next[i][0] = next[i][1] = -1;for(j = 0; j < N; j++){map[i][j] = -1;dp[i][j] = INF;}}for(i = 0; i < N; i++){dp[i][0] = 0;}for(i = 1; i < n; i++){int a, b, c;scanf("%d%d%d", &a, &b, &c);map[a][b] = map[b][a] = c;}build(0);vs[0] = d;//从家到0节点 run(0); for(i = 0; i < q; i++){int t, m;scanf("%d%d", &t, &m);printf(dp[0][m] <= t ? "I love you\n" : "Go to the hell\n");}}return 0;}

///////////更新

第一次做这个题时写出了上边的代码,并且通过了。过了几天发现再提交居然判失败。先在自己这里找问题,仔细地推敲了代码,结果再也没通过过……不知道是我的思维死区还是CSDN在卖萌,根据历史经验,我认为是后者。

不过还是把代码贴出来,有没有眼尖的能帮帮忙?

#include<iostream>#include<cstdio>#include<algorithm>#include<queue>using namespace std;typedef unsigned long long llu;const llu Inf = 0xffffffffffffffff;const llu N = 550;llu n, q, d;llu map[N][N];bool pass[N][N];llu cost[N];llu dp[N][N];bool used[N];int ord[N];vector<int> ch[N];int main(void){    while(cin >> n, n != 0){        cin >> q >> d;        fill((bool *)pass, (bool *)pass + N * N, false);        fill((llu *)dp, (llu *)dp + N * N, Inf);        fill(used, used + n, false);        for(int i = 1; i < n; i++){            int a, b;            llu c;            cin >> a >> b >> c;            map[a][b] = map[b][a] = c;            pass[a][b] = pass[b][a] = true;        }        queue<int> qu;        qu.push(0);        int orp = 0;        cost[0] = d;        while(!qu.empty()){            int v = qu.front(); qu.pop();            used[v] = true;            ord[orp++] = v;            for(int i = 0; i < n; i++){                if(pass[v][i] && !used[i]){                    qu.push(i);                    ch[v].push_back(i);                    cost[i] = map[v][i];                }            }        }        for(int i = n - 1; i >= 0; i--){            int v = ord[i];            dp[v][0] = 0;            dp[v][1] = cost[v];            if(ch[v].size() == 1){                int u = ch[v][0];                for(int i = 2; i < n; i++){                    dp[v][i] = dp[u][i - 1] < Inf ? dp[u][i - 1] + cost[i] : Inf;                }            } else if(ch[v].size() == 2){                int u = ch[v][0], w = ch[v][1];                for(int i = 2; i <= n; i++){                    llu mn = Inf;                    for(int j = 0; j < i; j++){                        if(dp[u][j] < Inf && dp[w][i - 1 - j] < Inf){                            mn = min(mn, dp[u][j] + dp[w][i - 1 - j]);                        }                    }                    dp[v][i] = mn < Inf ? mn + cost[v] : Inf;                }            }        }        for(int i = 0; i < q; i++){            llu t, m;            cin >> t >> m;            cout << (dp[0][m] * 2 <= t ? "I love you\n" : "Go to the hell\n");        }    }    return 0;}
0 0
原创粉丝点击