/**//* 一开始题目看的不是很懂,看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
搜索
最新评论
|
|