Dire Wolf HDU - 5115(区间dp)
Dire Wolf
Time Limit: 5000/5000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 3815 Accepted Submission(s): 2266
Dire wolves look like normal wolves, but these creatures are of nearly twice the size. These powerful beasts, 8 - 9 feet long and weighing 600 - 800 pounds, are the most well-known orc mounts. As tall as a man, these great wolves have long tusked jaws that look like they could snap an iron bar. They have burning red eyes. Dire wolves are mottled gray or black in color. Dire wolves thrive in the northern regions of Kalimdor and in Mulgore.
Dire wolves are efficient pack hunters that kill anything they catch. They prefer to attack in packs, surrounding and flanking a foe when they can.
— Wowpedia, Your wiki guide to the World of Warcra
Matt, an adventurer from the Eastern Kingdoms, meets a pack of dire wolves. There are N wolves standing in a row (numbered with 1 to N from left to right). Matt has to defeat all of them to survive.
Once Matt defeats a dire wolf, he will take some damage which is equal to the wolf’s current attack. As gregarious beasts, each dire wolf i can increase its adjacent wolves’ attack by bi. Thus, each dire wolf i’s current attack consists of two parts, its basic attack ai and the extra attack provided by the current adjacent wolves. The increase of attack is temporary. Once a wolf is defeated, its adjacent wolves will no longer get extra attack from it. However, these two wolves (if exist) will become adjacent to each other now.
For example, suppose there are 3 dire wolves standing in a row, whose basic attacks ai are (3, 5, 7), respectively. The extra attacks bi they can provide are (8, 2, 0). Thus, the current attacks of them are (5, 13, 9). If Matt defeats the second wolf first, he will get 13 points of damage and the alive wolves’ current attacks become (3, 15).
As an alert and resourceful adventurer, Matt can decide the order of the dire wolves he defeats. Therefore, he wants to know the least damage he has to take to defeat all the wolves.
The second line contains N integers ai (0 ≤ ai ≤ 100000), denoting the basic attack of each dire wolf.
The third line contains N integers bi (0 ≤ bi ≤ 50000), denoting the extra attack each dire wolf can provide.
题目大意:你是一个战士现在面对,一群狼,每只狼都有一定的主动攻击力和附带攻击力。你杀死一只狼。你会受到这只狼的(主动攻击力+旁边两只狼的附带攻击力)这么多伤害~现在问你如何选择杀狼的顺序使的杀完所有狼时,自己受到的伤害最小。(提醒,狼杀死后就消失,身边原本相隔的两只狼会变成相邻,而且不需要考虑狼围城环这种情况)
输入要求:总共T组数据,每组N只狼,按顺序输入全部狼的主动攻击力和然后再按顺序输入全部狼的附带攻击力
输出要求:Case #x: y x第几组数据,y最少受到的伤害
样例解释:
2
输入
3
3 5 7
8 2 0
输出
Case #1: 17
杀序号1的狼 3+2=5
杀序号2的狼 5+0=5
杀序号3的狼 7+0=7
总的伤害5+5+7=17;
10
1 3 5 7 9 2 4 6 8 10
9 4 1 2 1 2 1 4 5 1
Case #2: 74
主动伤害总和1+3+5+7+9+2+4+6+8+10=55;
附带伤害总和
因为数字比较多我这次列出全部过程
【1】3 5 7 9 2 4 6 8 10
【9】 4 1 2 1 2 1 4 5 1
附带伤害 4
【1 3】 5 7 9 2 4 6 8 10
【9 4】 1 2 1 2 1 4 5 1
附带伤害 1
【1 3 】5 【7】 9 2 4 6 8 10
【9 4】 1 【2】 1 2 1 4 5 1
附带伤害 1+1=2
【1 3】 5【 7】 9 【2】 4 6 8 10
【9 4】 1 【2】 1 【2】 1 4 5 1
附带伤害 1+1=2;
此时实际序列5 9 4 6 8 10
1 1 1 4 5 1
【1 3】 5【 7】 9 【2】 4 6【 8】 10
【9 4】 1 【2】 1 【2】 1 4 【5】 1
附带伤害 4+1=5
【1 3】 5【 7】 9 【2】 4【 6 8】 10
【9 4】 1 【2】 1 【2】 1 【4 5】1
附带伤害 1+1=2
剩下4只狼
5 9 4 10
1 1 1 1
从左边杀起,因这样每次只有右边有附带伤害
1+1+1=3
附带伤害总和4+1+2+2+5+2+3=19
总和伤害55+19=74
思路:区间dp,用贪心竟然wa了,肯定哪里有错了,呜呜呜
区间dp的伪代码
//mst(dp,0) 初始化DP数组 for(int i=1;i<=n;i++) { dp[i][i]=初始值 } for(int len=2;len<=n;len++) //区间长度 for(int i=1;i<=n;i++) //枚举起点 { int j=i+len-1; //区间终点 if(j>n) break; //越界结束 for(int k=i;k<j;k++) //枚举分割点,构造状态转移方程 { dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]); } }
题目AC代码
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cstdlib> #include<queue> #include<set> #include<vector> using namespace std; #define INF 0x3f3f3f3f #define eps 1e-10 #define ll long long int const maxn = 205; const int mod = 1e9 + 7; int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } int attack[210]; int extre[210]; int dp[210][210]; //第i到第j个的最小受到伤害 int main() { int t; cin>>t; int ca=1; while(t--) { int n; cin>>n; for(int i=1;i<=n;i++) cin>>attack[i]; for(int i=1;i<=n;i++) cin>>extre[i]; extre[0]=0; //初始边界情况 extre[n+1]=0; for(int i=1;i<=n;i++)
//刚开始我写成memset(dp,INF,sizeof(dp));这样是错的因为下面有dp[i][k-1]+dp[k+1][j]在每次循环时第一遍因为j==k,所以k+1>j
// 如果按memset初始化,dp[k+1][j]和[dp[i][j]都是超级大的数,min就会出错。
for(int j=i;j<=n;j++) dp[i][j]=INF; for(int i=0;i<=n;i++)
{
dp[0][i]=0;
dp[i][n+1]=0;
}
for(int len=1;len<=n;len++)
for(int i=1;i<=n;i++)
{
int j=i+len-1;
if(j>n)
break;
for(int k=i;k<=j;k++)
{
dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+attack[k]+extre[i-1]+extre[j+1]);
}
}
printf("Case #%d: %d\n",ca++,dp[1][n]);
}
}