您的位置:首页 > 理论基础 > 计算机网络

[2010杭州赛区网络赛1006]Fate Stay

2010-09-19 21:08 302 查看
比赛三个多小时一直在写1006,不停WA,回来照着原来思路重写之后一下就A掉了,很无语。

这道题如果不能使用双倍攻击,那就是道贪心大水题,加了可以使用M次双倍以后就是DP。

dp[i][j]表示前i个火鸟使用j次双倍攻击,那么应该保存两个值,一个是当前已杀怪次数cnt,另一个是当前面对的怪剩下的生命值。

dp[i][j]可以由dp[i-1][j]或dp[i-1][j-1]转移而来,双倍时贪心选择在火鸟攻击初用,杀怪过程同样贪心。

代码如下:

#include<iostream>
using namespace std;
const int inf = 2000000000;
const int maxn = 10010;
const int maxk = 100010;
const int maxm = 110;
struct nod_t
{
int cnt, rem;
};
int N, M, K;
int f[maxn], k[maxk];
nod_t dp[maxn][maxm];
//dp[i][j]表示前i个火鸟使用j次double后,
//杀死怪物的最多次数cnt,和正要杀的怪物的剩下的生命rem;

nod_t Get0(int i, int j)//计算dp[i-1][j]状态的下一个状态,输入保证i<j
{
nod_t nod0;

if(dp[i-1][j].rem==inf) //这时,dp[i-1][j]的cnt已经等于K了.
{
nod0.cnt = dp[i-1][j].cnt;
nod0.rem = inf;
}
else
{
if(f[i] < dp[i-1][j].rem) //当前火鸟f[i]太小,杀不过当前要杀的怪
{
nod0.cnt = dp[i-1][j].cnt;
nod0.rem = dp[i-1][j].rem - f[i]; //那么就拼掉f[i]的生命
}
else if(f[i] == dp[i-1][j].rem) //1vs1拼掉
{
int killed = dp[i-1][j].cnt;
nod0.cnt = killed + 1;
nod0.rem = k[killed+1];
}
else  //当前火鸟可以杀至少一个怪.
{
int life = f[i];
int killed = dp[i-1][j].cnt;

life -= dp[i-1][j].rem;
killed++;

while(life >= k[killed+1]) //能够杀死下一个怪
{
killed++;
life -= k[killed];
if(life==0) break; //如果当前生命为0,那么火鸟死亡
}
nod0.cnt = killed;
nod0.rem = k[killed+1];
}
}
return nod0;
}
nod_t Get1(int i, int j) //计算dp[i-1][j-1]状态的下一个状态,输入保证j>0
{
nod_t nod1;
if(dp[i-1][j-1].rem==inf)
{
nod1.cnt = dp[i-1][j-1].cnt;
nod1.rem = inf;
}
else
{
if(2*f[i] < dp[i-1][j-1].rem)
{
nod1.cnt = dp[i-1][j-1].cnt;
nod1.rem = dp[i-1][j-1].rem - 2*f[i];
}
else if(2*f[i] == dp[i-1][j-1].rem)
{
int killed = dp[i-1][j-1].cnt;
killed++;
nod1.cnt = killed;
nod1.rem = k[killed+1];
}
else
{
int life = 2*f[i];
int killed = dp[i-1][j-1].cnt;

life -= dp[i-1][j-1].rem;
killed++;    //至少能杀死一个怪

while(life >= k[killed+1]) //能够杀死下一个怪
{
killed++;
life -= k[killed];
if(life==0) break; //如果当前生命为0,那么火鸟死亡
}
nod1.cnt = killed;
nod1.rem = k[killed+1];
}
}
return nod1;
}
int main()
{
int i, j;
while(scanf("%d %d %d", &N, &M, &K)==3)
{
if(N==0&&M==0&&K==0) break;

for(i = 1; i <= N; i++)
{
scanf("%d", &f[i]);
}
for(i = 1; i <= K; i++)
{
scanf("%d", &k[i]);
}
k[K+1] = inf; //结束标记

if(M>N) M = N;  //trick
memset(dp, 0, sizeof(dp));
dp[0][0].cnt = 0;
dp[0][0].rem = k[1];

for(i = 1; i <= N; i++)
{
for(j = 0; j <= M && j <= i; j++)
{
nod_t nod0, nod1; //nod0,nod1分别是由dp[i-1][j],dp[i-1][j-1]转换来的状态

if(i!=j) //nod0在i<j的情况下合法
{
nod0 = Get0(i, j);
}
if(j!=0) // j>0合法
{
nod1 = Get1(i, j);
}

if(j==0)
dp[i][j] = nod0;  //只能为nod0
else if(i==j)
dp[i][j] = nod1;  //同上
else
{
//第一优先选杀怪数多的,第二优先下个怪生命少的,
if(nod0.cnt > nod1.cnt)
dp[i][j] = nod0;
else if(nod0.cnt < nod1.cnt)
dp[i][j] = nod1;
else
{
if(nod0.rem < nod1.rem)
dp[i][j] = nod0;
else
dp[i][j] = nod1;
}
}
}//for j
}// for i

// 要在前面加上if(M>N) M=N,因为数据中有M>N的情况
printf("%d/n", dp
[M].cnt);

/*
int ans = 0;
for(j = 0; j <= M && j <= N; j++)
{
if(dp
[j].cnt > ans)
ans = dp
[j].cnt;
}
printf("%d/n", ans); */
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: