 /**//*
一開始題目看的不是很懂,看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
搜索
最新評論

|
|