URAL 1651 Shorest Subchain DP #by Plato

17 篇文章 0 订阅

http://acm.timus.ru/problem.aspx?space=1&num=1651

题意: 给出一个有向图的chain,求关于这个chain的shortest subchain(起点、终点与原chain相同&边出现的顺序与原chain相同)。

Idea:

DP :

依次处理每个a[i] : f[a[i]]=f[a[i-1]] + 1;

个人感觉这道题,难不在DP方程,而是想到用DP来做这道题。当时我看到这道题,第一反应就是图论,尝试用缩点的方法,再然后就放弃了。

小插曲:

这道题的路径输出也卡了我好久,最初我的思路是去记录 f[i] 对应的上一个结点j ,

f[i] = f[j] + 1 ,pre[i] = j; 然后一直WA,想不清楚。

对比了下正确的程序,只是在记录路径上的不同,正确的程序记录的是

f[i] = f[j] + 1, pre[i的位置]  = j所在的位置 ,最后通过a[N]的位置,依次向前找。

然后还是一直想不清楚,觉得没有什么区别,举出反例。今天早上突然就闪过一个想法:假设答案是 KàN,N是最终结点且在中间的位置mid,假如在mid之后K再次被更新。。。。。快一个星期了,终于又答案了。(KEY:分类讨论、假设-验证)

反例:  1,2,3,4,9,10,2,9,7,8,10

正确答案:1,2,3,4,9,10; 错误:1,2,9,10

二、最短路

搜题解的时候发现有最短路的解法,具体忘了。


#include <cstdio>
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#define OP(s) cout<<#s<<"="<<s<<" ";
#define TP(i,j,k) cout<<#i<<"="<<i<<" "<<#j<<"="<<j<<" "<<#k<<"="<<k<<endl;
#define PP(s) cout<<#s<<"="<<s<<endl;
using namespace std;

int main()
{
    freopen("test.txt","r",stdin);
    int N;
    while (~scanf("%d",&N))
    {
        static int a[100010];
        for (int i = 1; i <= N; i++)
            scanf("%d",a+i);

        static int f[10010],pre[100010],pos[10010];
        for (int i = 0; i < 10010; i++) f[i] = 1<<29;
        memset(pre,0,sizeof(pre));
        f[a[1]] = 0;
        pos[a[1]] = 1;
        for (int i = 2; i <= N; i++)
        {
            if (f[a[i-1]] + 1 < f[a[i]])
            {
                f[a[i]] = f[a[i-1]] + 1 ;
                pre[i] = pos[a[i-1]];
                pos[a[i]] = i;
            }
        }

        int p = pos[a[N]];
        static int ans[10010];
        int sa = 0;
        while (p != 1)
        {
            ans[++sa] = a[p];
            p = pre[p];
            //if (p == a[1]) break;
        }
        printf("%d",a[1]);
        for (int i = sa; i > 0; i--) printf(" %d",ans[i]);
        puts("");
    }

    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值