 /**//*
一开始题目看的不是很懂,看watashi的解题报告的

题意:n个团员,坐成一排。团长列出m对关系,
每分钟报一个,如果关系中的两个人相邻,则其中一个人要离开
团员想走的越多越好,团长想走的人越少越好,问团长该怎么安排
这m对关系的顺序

显然团长可以先贪心地把原本不相邻的关系先报掉,这样没人会走
接下来的就是一些连续的一段
这个问题可以dp预处理,dp[n]表示n个人连成一段最少离开的人数

团长会枚举断开的点然后缩小规模解决
1 - 2 - 3 n-1 - n
枚举断开第i段的话,现在团员当然会选择让离开的人最多
即 max(dp[i-1]+dp[n-i]+1 , dp[i]+dp[n-i-1]+1)
而团长就通过枚举哪一段来取得最小值
min{ max(dp[i-1]+dp[n-i]+1 , dp[i]+dp[n-i-1]+1) }
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;

const int INF = 1000000000;

int dp[512];

void init()
  {
dp[2] = 1;
for(int n = 3 ; n <= 500 ; n++)
 {
dp[n] = INF;
for(int i = 1 ; i < n ; i++)
 {
dp[n] = min( dp[n] , max(dp[i-1]+dp[n-i] , dp[i]+dp[n-i-1])+1 );
}
}
}

int main()
  {
//freopen("in","r",stdin);
init();
int n , m;
while(~scanf("%d%d",&n,&m) )
 {
int a ,b;
vector<int> vt;
for(int i = 0 ; i < m ; i++)
 {
scanf("%d%d",&a,&b);
if(a>b)swap(a,b);
if(b==a+1)
 {
vt.push_back(a);
}
}
sort(vt.begin() , vt.end());
int ans = n;
for(vector<int>::iterator it = vt.begin() ; it != vt.end();it++)
 {
int cnt = 1;
while( it+1 != vt.end() && (*it)+1 == *(it+1))cnt++,it++;
cnt ++;
ans -= dp[cnt];
}
printf("%d\n",ans);
}
return 0;
}
|
|
常用链接
随笔分类
Links
搜索
最新评论

|
|