UVALive 6680 Join the Conversation (DP)

33 篇文章 0 订阅

大体题意:

给你n 行对话,刚开始告诉你人的姓名,其次是对话内容,要求求一个最长的长度,使得下一个对话的内容包括上一个对话的人的姓名?

思路:

赛后补得题目:

Dp思想!

令dp[i]表示枚举到第i 行 所能得到的最大值!

===========================================

记录一下整个思考的过程吧,因此错了很多遍!

首先想到的是利用map<string,Node> 来记录,第一个string 记录对话人的姓名,第二个结构体里存放一些东西!

struct Node{

    int d,pos,last;

}

其中d 就表示dp记录的东西,走到这个人得到的最大值,pos 是记录到这个人最大的位置,last 表示前面的路径!

然后转移就很好转移了,在枚举第i 行时,先确保这个人的map 一定存在,初始化他的Node,然后在枚举这个人的内容,如果发现在map中存在了,就把存在的那个人的信息(d)转移到当前这个人,然后在记录路径!

这样整个过程就相当于用map 来记录dp了,打印路径还得需要5w的string 数组进行初始化!

以上整个思路 是超时的!

==============================================

针对以上情况,很明显超时超在 5w个string 数组的初始化上,那么优化肯定就不能再用他了,所以直接在开两个数组单独记录dp 和路径pre

这样也有个好处 不用每次都memset,因为只需要在枚举新的一行时 初始化当前的dp 和pre 即可!

这样省了好多时间,也去掉了Node 中的last变量!

那么最后统计答案 只需要统计 1~n 的最大dp 即可!  然后记录最大值的位置,pre回去即可!

详细见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
#include <sstream>
#include <stack>
#include <iostream>
using namespace std;
const int maxn = 50000 + 10;
struct Node{
    int d, pos;
};
int dp[maxn],pre[maxn];
map<string,Node>mp;
stack<int>sk;
int cur = 0;
int main(){
    int n;
    string s,name,t;
    while(scanf("%d%*c",&n) == 1){
        mp.clear();
        for (int i = 1; i <= n; ++i){
            getline(cin,s);
            stringstream ss(s);
            ss >> name;
            name.resize(name.length() - 1);
//            names[i] = name;
//            cout << name <<endl;
            if (!mp.count(name)){
                Node u;
                u.d = 1;
                u.pos = i;
//                u.last = -1;
                mp[name] = u;
            }
            pre[i] = -1;
            dp[i] = 1;
            while(ss >> t){
                if (!mp.count(t) || t == name)continue;
                if (dp[i] < mp[t].d + 1){
                    dp[i] = mp[t].d + 1;
                    pre[i] = mp[t].pos;
                }
            }
            if (mp[name].d < dp[i]){
                mp[name].d = dp[i];
                mp[name].pos = i;
            }
        }
        int ans = 0,p = 1;
        for (int i = 1; i <= n; ++i){
            if (ans < dp[i]){
                p = i;
                ans = dp[i];

            }

        }
        printf("%d\n",ans);
        while(p != -1){
            sk.push(p);
            p = pre[p];
        }
        int cnt = 0;
        while(!sk.empty()){
            if (cnt++)printf(" ");
            printf("%d",sk.top());
            sk.pop();
        }
        puts("");
    }
    return 0;
}

/**
5
@Petr: Leaving for #NEERC tomorrow!
@Roman: This #NEERC is going to be awesome!
@Stone in forest: Nothing happened today.
@NEERCNews: @Petr Don’t forget an umbrella :)
@Lydia: @NEERCNews cares about @Petr - so cute ^ ^
6
@Petr: Leaving for #NEERC tomorrow!
@Roman: This #NEERC is going to be awesome!
@Stone in forest: Nothing happened today.
@NEERCNews: @Petr Don’t forget an umbrella :)
@Lydia: @NEERCNews cares about @Petr - so cute ^ ^
@Lydia: @Lydia @NEERCNews @Petr it won’t be raining though!

**/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值