UESTC 28题-补刀

好吧,我又来不务正业了,UESTC-28题链接:

http://acm.uestc.edu.cn/#/problem/show/28

这道题没涉及什么算法,自己写了个暴力破解的版本如下,但是运行时间太长了,百思不得其优化算法,于是到网上搜索合适的代码。。

#include<cstdio>
#include<cstdlib>
typedef struct node
{
	int A;
	int T;
}node;

void func(node* cai,int n,int myA,int bossH);

int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		if(n<=1)break;//输入竞争补刀的玩家个数 
		node * cai=(node *)malloc(sizeof(node)*(n-1));//创建竞争补刀的敌方单位 cai,都是些菜,想跟我补刀? 
		int ii=0;
		int myA,bossH;

		while(ii<n-1)
		{
			scanf("%d%d",&cai[ii].A,&cai[ii].T);
			ii++; 


		}
		scanf("%d%d",&myA,&bossH);
		
	
		
		func(cai,n,myA,bossH);
		
		free(cai);
		
	}
	return 0;
}
void func(node* cai,int n,int myA,int bossH)
{
	
	int sumA=0;
	int t=1;//按时间来算伤害
	int T_start,T_end;
	int H_kill=bossH-myA;//斩杀线 
	int flag=1;//标记T_start计数器 
	while(t  )
	{
		int pri_sumA=sumA;//当前t时间之前一个时刻(t-1)的boss损失血量 
		for(int i=0;i<n-1;i++)//求出最早出手时间T_start,和boss的致死时间T_dead ,以及最晚出手时间 
		{
			
		
			if(t%cai[i].T==0)sumA+=cai[i].A;//sumA是BOSS已损血量 
			
		}
		if(sumA>=H_kill && flag)//达到斩杀线,且之后不再计算 
		{
			T_start=t;
			flag=0;
		}
		if(sumA>=bossH)
		{
			T_end=t;
			break;
			
		
		}
		++t;
		
	}
	while(T_start<=T_end)
	{
		int flagg=1;
		for(int i=0;i<n-1;i++)
		{

			if(T_end%cai[i].T==0)
			{
				if(cai[i].A>myA)
				{
					T_end--;
					flagg=0;
					break;
					
				}
			
			}
			
		}
		if(flagg)break;
	
	}
	while(T_start<=T_end)
	{
		int flagg=1;
		for(int i=0;i<n-1;i++)
		{

			if(T_start%cai[i].T==0)
			{
				if(cai[i].A>myA)
				{
					T_start++;
					flagg=0;
					break;
					
				}
			
			}
			
		}
		if(flagg)break;
	
	}
	if(T_start>T_end)
	{
		printf("Impossible\n");
		return;
	}
	else 
	{
		printf("%d %d\n",T_start,T_end);
		return ;
	}
} 


最终搜到的代码可以AC,但是自己有点看不懂,果断请教果爷,经过果爷语音一步步提示,终于明白了别人代码的精髓,贴上代码如下:(自己加了注释)

#include<stdio.h>
int k;
struct stu
{
    int x;// 时间间隔为T的时候DPS之和,输出的最大伤害 
    int mx;//时间间隔为T的时候最大的DPS 
}bu[110];//bu[T],按时间点T创建的结构体数组 
int f(int j)
{
    int i,m=0,mxx=0;
     for(i=1;i<=100;i++)
              if(bu[i].mx)
                m=m+(j/i)*bu[i].x;
       return m;
}
int main()
{
    int i,j,x,t,m,n,P,H,l,mxx;// 
    double s,x1,t1,n1,y1;//s代表所有彩笔的单位时间DPS之和 ,n1是斩杀线/单位时间只和 
    while(scanf("%d",&n)&&n)
    {
        for(i=0;i<=100;i++)
            bu[i].mx=bu[i].x=0;//bu[]赋初值 
            s=0;
        for(i=1;i<n;i++)//这里的i只计数,不干别的 
        {
            scanf("%d%d",&x,&t);
            bu[t].x=bu[t].x+x;//bu[t]代表时间t时刻,所有彩笔的当前输出总和 
            if(x>bu[t].mx)bu[t].mx=x;//时间t时刻,当前的最大输出记录为bu[t].mx 
            x1=x;
            t1=t;
            s=s+x1/t1;//s是所有彩笔的单位时间DPS之和,用来计算靠近斩杀线的时间 
        }
        scanf("%d%d",&P,&H);
        x1=H;
        y1=P;
        n1=(x1-y1)/s;//n1是靠近斩杀线的时间 下一步赋值为n 
        n=n1;
        if(n==0)n=1;
        l=0;
        for (i=n;i<=100+n;i++)//从靠近斩杀线的时间n开始枚举 
        {     m=0;mxx=0;
           for(j=1;j<=100;j++)//时间t的枚举,从1到100; 
           {
              if(bu[j].mx)
              {
                 m=m+(i/j)*bu[j].x;//m是输出伤害j时间下,输出次数*输出伤害=总输出数 
                 if(i%j==0&&bu[j].mx>mxx)
                 mxx=bu[j].mx;//所有时刻的最高输出???不明白 buj.x改为mx 
              }
           }
           if(m+P>=H&&mxx<=P){l=i;break;}//P是我的输出,m是总伤害 
           else if(m+P>=H)
           
           break;
        }
        if(l==0)
        {
            printf("Impossible\n");
            continue;
        }
        printf("%d",l);
        n1=x1/s;
        n=n1;
        for(j=n+100;j>=l;j--)
        {
            m=0; mxx=0;
             for(i=1;i<=100;i++)
          {
              if(bu[i].mx)
             {
                m=m+(j/i)*bu[i].x;
                if(j%i==0&&bu[i].mx>mxx)
                mxx=bu[i].mx;
             }
           }
           if(m+P>=H&&mxx<=P&&f(j-1)<H){printf(" %d\n",j);break;}
        }
    }
    return 0;
}

心得:结构体数组的构建,暴力方法无法破解,要考虑换个方式创建个合适的数组,嗯,思维要灵活!!!感谢果爷给我的讲解~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值