ACM-ICPC Live Archive 3222 Joke with Turtles

本文介绍了一种使用区间动态规划方法解决特定排列问题的算法。问题要求在不冲突的前提下选择尽可能多的乌龟,使得它们各自描述的前后乌龟数量的信息一致。通过将乌龟的信息转换为区间表示,并利用DP进行求解,最终输出说谎的乌龟数目及编号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

poj 2168 相同的题目

区间DP

题意:输入n,表示有n个海龟在一条直线上,乌龟可以站在相同的位置(即坐标可以相同),下面n行,每行两个数字,表示第i个乌龟给出的信息,第一个数字表示它前面有多少只乌龟,第二个数字表示它后面有多少个乌龟。并不是每个乌龟的信息都是正确,有些乌龟的信息是假的,或者和别的乌龟信息冲突,你的任务是选出尽量多的乌龟,使他们的信息不冲突,然后输出有多少个乌龟说谎,和那些乌龟的编号,可能有多种情况,只要保证说谎的乌龟数最少,输出哪种情况都可以

 

分析:乌龟可以站在一样的位置,我们给乌龟排名,可以把它们放在不同的位置 例如  1 2 3 3 3 4 4 5 , 虽然有些排名相同,但是放在不同位置,这样方便我们处理

有n个乌龟,所以我们要准备n个位置。对于一个乌龟,它前面和后面分别为a,b人,那么可以知道,它的位置一定在[a+1,n-b]内,至于它确切在哪个位置并不重要,因为这个区间内的乌龟排名相同的。这样我们就转化为,用一个区间来表示乌龟,这是非常重要的一步

然后没读入一个乌龟,我们就在那个区间计数,w[i][j]表示在这个区间内有多少个乌龟,如果乌龟数超过了(j-i+1)那么不能再计数,因为这个区间最多只容纳这些乌龟

想想我们的问题,是找出最少的说慌的乌龟,反过来就是可以共存的乌龟数最多,而乌龟用区间表示了,那不就是变成了选最多的区间?就是这样,而且要满足,选出来的区间不能重叠

 

关于“所选区间不能重叠”,这个东西不好解释,但,这却是一个显然的事实(往往越是显然的越难理解)。可以这样想,我们是允许排名相同的,但是我们已经给每只乌龟排在一个位置了,只允许是排名相同,不能是位置相同的,如果区间重叠,就变成了位置相同,这和我们最开始的定义是相矛盾的

 

这样问题变为,在总区间[1,n]里面,选一些区间,这些区间不重叠,而且每个区间有权值(表示这个区间有多少乌龟,这些乌龟,不就是排名相同的乌龟嘛,只是安排了不同位置,但位置一定在这个区间内),使得所选区间加起来权值最大,只是个典型的区间模型

dp[i]表示[1,i]区间的最大权值和,目标状态为dp[n],另外在dp过程中要记录路径

方程: dp[i] = max { dp[j] + w[j+1][i]  }

 

记录路径是为了输出。

dp完了我们从n沿路径返回,没找到一个前驱,其实可以确定一个区间w[pre+1][now] , 这个区间对应的其实是乌龟,表示这些乌龟背选中了,它们信息不冲突,不说谎,把这些乌龟标记掉

这时候想想我们一开始为什么要给w[i][j]计数,其实就是记录里面的乌龟数,为什么w[i][j]>(j-i+1)后不能再计数,因为可以知道,肯定有一些乌龟是矛盾的,这个区间不能放下这么多乌龟

然后输出没有被选中的乌龟即可

 

程序跑了200ms左右,是因为在选乌龟的时候是直接暴力扫描的,没有做优化

有优化想法欢迎分享

 

#include <cstdio>
#include <cstring>
#include <vector>
#include <utility>
using namespace std;
#define N 1010

int n;
int w[N][N];
int dp[N] , p[N];
struct tur
{
   int a,b,c;
}t[N];

void solve()
{
   memset(dp,0,sizeof(dp));
   memset(p,-1,sizeof(p));

   for(int i = 1; i <= n; i++)
      for(int j = 0; j<n; j++)
         if(dp[j] + w[j+1][i] > dp[i])
         {
            dp[i] = dp[j] + w[j+1][i];
            p[i] = j;
         }

   bool used[N];
   memset(used,false,sizeof(used));
   int pre,now,count,c;
   now = n;
   count = 0;
   while(1) //沿路径返回并标记说了真话的乌龟
   {
      pre = p[now];
      if(pre == -1) break;
      //区间为[pre+1,now]
      c = w[pre+1][now]; //有多少只重叠的乌龟
      for(int i=0; i<n && c; i++)
         if(t[i].a == pre && t[i].b == n-now)
         {
            used[i] = true;
            c--;
            count++;
         }
      now = pre;
   }
   printf("%d",n-count);
   for(int i=0; i<n; i++)
      if(!used[i])
         printf(" %d",i+1);
   printf("\n");
}

int main()
{
   while(scanf("%d",&n)!=EOF)
   {
      memset(w,0,sizeof(w));
      for(int i=0; i<n; i++)
      {
         int a,b;
         scanf("%d%d",&a,&b);
         t[i].a = a; t[i].b = b;
         t[i].c = n - t[i].a - t[i].b;
         w[a+1][n-b]++;
         if(w[a+1][n-b] > t[i].c)
            w[a+1][n-b] = t[i].c;
      }
      solve();
   }
   return 0;
}

 

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值