试题 算法提高 宰羊
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
炫炫回了内蒙,肯定要吃羊肉啦,所有他家要宰羊吃。
炫炫家有N只羊,羊圈排成一排,标号1~N。炫炫每天吃掉一只羊(这食量!其实是放生啦),吃掉的羊的邻居会以为它被放生了,然后又会告诉他们的邻居,这样一直传播下去,除非某个邻居已经被“放生”了。每一天,所有知道某羊被“放生”了这个消息的羊都会很不满,如果不给他们巧克力的话,他们就会很造反,炫炫已经知道他要吃掉哪些羊,他可以任意安排吃的顺序,然后使巧克力的用量最小,请求出这个最小值。
输入格式
本题有多组数据,第一行为数据组数T。
对于每组数据
第一行:两个用空格隔开的整数:N和M,表示羊的数量和需要吃掉的数量
第二行:有M个数,表示要吃那些羊。
输出格式
T行,为每组数据的答案。
样例输入
2
8 1
3
20 3
3 6 14
样例输出
7
35
数据规模和约定
T=10
N<=10000
M<=100
代码
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int n,m;
short int M[102];//保存吃掉哪一些羊
int dp[102][102]={0};
int dfs(int left,int right){
if(left>=right||right<=left) return 0;
int la,ra;
for(int i=0;i<m+2;i++){//dp的下标如果直接使用left和right的话,会内存超限
if(M[i]==left){//为了避免超限,将left和right映射为M[i]的下标
la=i;
}
if(M[i]==right){
ra=i;
}
}
if(dp[la][ra]!=0) return dp[la][ra];
bool flag=false;
int _min=1000000000;
for(int i=1;i<=m;i++){//枚举在区间left-right中需要被吃掉的羊
if(M[i]>left&&M[i]<right){
flag=true;
//如果吃掉的是M[i]这只羊,那么吃掉这只羊的最小代价是:吃掉左区间所有样的代价+吃掉有区间所有样的代价+本次吃到这只羊的代价。
_min=min(_min,dfs(left,M[i])+dfs(M[i],right)+right-left-2);
// cout<<M[i]<<endl;
}
}
if(flag==false){
return 0;
}else{
dp[la][ra]=_min;
return _min;
}
}
int main(){
int t;
cin>>t;
while(t>0){
memset(M,0,sizeof(int)*102);
memset(*dp,0,sizeof(int)*102*102);
cin>>n>>m;
M[0]=0;
for(int i=1;i<=m;i++){
cin>>M[i];
}
M[m+1]=n+1;
sort(M,M+m);
cout<<dfs(0,n+1)<<endl;
t--;
}
return 0;
}