不想打题面了,题面戳这里

这道题目的模型转换地有点猛。首先我们肯定需要让老板把那些不相邻的人的卡牌放在前面,这样他们就作废了。然后剩下的卡牌就都是相邻人之间的了。我们就可以把这个序列分成若干个联通块,每个联通块内相邻的人之间有连边。此时显然不同联通块是互不干扰的,我们只需要知道每个联通块内剩下的人最多可以是多少就可以了。这个我们就可以dp了。

\(f_i\)表示大小为\(i\)的联通块内最多能剩多少人,那么方程就和显然了。

\[f_i = \max \{ f_j+f_{i-j-1} \},j < i
\]

最后对统计所有联通块答案求和即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std; const int maxn = 510;
int N,M,f[maxn],father[maxn],ans; inline int find(int x) { return father[x] != x?father[x] = find(father[x]):x; } int main()
{
freopen("3161.in","r",stdin);
freopen("3161.out","w",stdout);
f[1] = 1; f[0] = 0;
for (int i = 2;i <= 500;++i) for (int j = 1;j < i;++j) f[i] = max(min(f[j-1]+f[i-j],f[j]+f[i-j-1]),f[i]);
while (scanf("%d %d",&N,&M) != EOF)
{
ans = 0;
for (int i = 0;i < N;++i) father[i] = i;
for (int i = 1,a,b;i <= M;++i)
{
scanf("%d %d",&a,&b);
if (a > b) swap(a,b);
if (b - a == 1)
{
int r1 = find(a),r2 = find(b);
father[r2] = r1;
}
}
for (int i = 0,j;i < N;++i)
{
for (j = i;j < N&&find(j) == i;++j);
ans += f[j-i]; --j;
}
printf("%d\n",ans);
}
fclose(stdin); fclose(stdout);
return 0;
}

最新文章

  1. [LeetCode] Best Meeting Point 最佳开会地点
  2. sqlserver 2005 数据误删恢复
  3. 解决python编码格式错误问题
  4. DOM example
  5. python--基础学习(三)字符串单引号、双引号、三引号
  6. 转:软件架构入门 (from 阮一峰)
  7. ecshop 商品页面添加商品标签:
  8. iOS 使用Xcode和Instruments调试解决iOS内存泄露(链接转)
  9. Git教程之安装配置(1)
  10. python学习_应用pickle模块封装和拆封数据对象
  11. VirtualBox 主机与虚拟机互通
  12. 01_GIT基础、安装
  13. CSS操作笔记
  14. 为什么我的会话状态在ASP.NET Core中不工作了?
  15. React事件杂记及源码分析
  16. ☆ [HNOI2012] 永无乡 「平衡树启发式合并」
  17. Linux性能优化实战:系统的swap变高(08)
  18. JavaMap的一些常用方法
  19. JS求数组差集的几种方法
  20. JVM 垃圾回收机制

热门文章

  1. input宽度超出
  2. http协议组成(请求状态码)
  3. 操作 Java 数组的 12 个最佳方法
  4. PyQuery网页解析库
  5. Pythony的数据类型和变量使用方法详解
  6. HDU 5446 Unknown Treasure (卢卡斯+CRT
  7. Codeforces Round #481 (Div. 3) 全题解
  8. 动态调试smali代码
  9. python 函数function
  10. Git Cheatshell - Pro Git