hdu 1069 Monkey and Banana---dp(也可用 求最长路+floyd水过)

解法一:把每个方块,当成3个点,地面设为p[0] 点,有向图的   最长路,用 floyd 水过

其实应该用  dp 做的。。



#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;

int n,i,j,k;

struct node{
	int a,b,len;
}p[100];
int map[100][100];
int main()
{
	int t=0;
	while(scanf("%d",&n),n){
		t++;
		int ans=1,x,y,z;
		for(i=1;i<=n;i++)
		{
			scanf("%d%d%d",&x,&y,&z);//一个方块  相当于  3个点
			p[ans].a=x;
			p[ans].b=y;
			p[ans++].len=z;
			p[ans].a=x;
			p[ans].b=z;
			p[ans++].len=y;
			p[ans].a=z;
			p[ans].b=y;
			p[ans++].len=x;
		}
		p[0].a=9999999;  // 地面  每个点 都能到,所以赋值为  最大
		p[0].b=9999999;
		p[0].len=0;
		for(i=0;i<ans;i++)
			for(j=0;j<ans;j++)
				map[i][j]=-9999999;    //将map 都赋值为  最小
		for(i=0;i<ans;i++)
			for(j=0;j<ans;j++)
				if((p[i].a>p[j].a&&p[i].b>p[j].b) || (p[i].a>p[j].b&&p[i].b>p[j].a))
					map[i][j]=p[j].len;    //满足条件,i点到j点的  距离就为  j的 长度
		for(k=0;k<ans;k++)
			for(i=0;i<ans;i++)
				for(j=0;j<ans;j++)
					if(map[i][k]+map[k][j]>map[i][j])
						map[i][j]=map[i][k]+map[k][j];//floyd  算法  水过
		int max=-1;
		for(i=0;i<ans;i++)
			if(map[0][i]>max)
				max=map[0][i]; //挑出最大的长度
		printf("Case %d: maximum height = %d\n",t,max);
	}
}
解法二:

哈哈,研究了一下dp的做法,做出来了

解析:就是将所有 方块按 面积 (从小到大)排序。之后,小面积的方块一定不能  覆盖  大面积的方块,大面积的方块可能 覆盖小面积的方块。

问题就变成了,和求 最长上升子序列  差不多。

最长上升子序列:3 6 4 8 2 -1 9 4         

 前面的数一定不能 覆盖 后面的数,但后面的数 可能 覆盖 前面的数(如果后面的数>前面的数,就可以排在那个数的后面)

#include<stdio.h>  
#include<string.h>  
#include<stdlib.h>  
#include<algorithm>  
#include<iostream>  
#include<math.h>  
using namespace std;  
  
int n,i,j,k;  
int dp[100];
struct node{  
    int a,b,len,s;  
}p[100];   

bool comp(node a,node b)
{
	return a.s<b.s;
}
int main()  
{  
    int t=0;  
    while(scanf("%d",&n),n){  
        t++;  
        int ans=1,x,y,z;  
        for(i=1;i<=n;i++)  
        {  
            scanf("%d%d%d",&x,&y,&z);//一个方块  相当于  3个点  
            p[ans].a=x;  
            p[ans].b=y; 
	    p[ans].s=x*y;
            p[ans++].len=z;  
            p[ans].a=x;  
            p[ans].b=z; 
	    p[ans].s=x*z;
            p[ans++].len=y;  
            p[ans].a=z;  
            p[ans].b=y;  
	    p[ans].s=z*y;
            p[ans++].len=x;  
        }  
        sort(p+1,p+ans,comp);
		memset(dp,0,sizeof(dp));
		dp[1]=p[1].len;     //赋初值
		int flag=0;
		for(i=1;i<ans;i++)
		{
			flag=0;
			for(j=1;j<i;j++)
				if((((p[i].a>p[j].a)&&(p[i].b>p[j].b))||((p[i].a>p[j].b)&&(p[i].b>p[j].a))))
				{
					flag=1;
					if(dp[j]+p[i].len > dp[i])
						dp[i]=dp[j]+p[i].len;
				}
			if(flag==0)//赋初值,一开始这没加,只给上面的 dp[1]=p[1].len; 赋了,就错了,调试了一下,就发现有bug了
				dp[i]=p[i].len;//例如:2   10 10 1000    5 30 10000 这个用例就过不了。。
		}
		int max=-1;
		for(i=1;i<ans;i++)
			if(dp[i]>max) max=dp[i];
        printf("Case %d: maximum height = %d\n",t,max);  
    }  
} 


后来问同学,原来这样赋初值就可以

#include<stdio.h>  
#include<string.h>  
#include<stdlib.h>  
#include<algorithm>  
#include<iostream>  
#include<math.h>  
using namespace std;  
  
int n,i,j,k;  
int dp[100];
struct node{  
    int a,b,len,s;  
}p[100];   

bool comp(node a,node b)
{
	return a.s<b.s;
}
int main()  
{  
    int t=0;  
    while(scanf("%d",&n),n){  
        t++;  
        int ans=1,x,y,z;  
        for(i=1;i<=n;i++)  
        {  
            scanf("%d%d%d",&x,&y,&z);//一个方块  相当于  3个点  
            p[ans].a=x;  
            p[ans].b=y; 
			p[ans].s=x*y;
            p[ans++].len=z;  
            p[ans].a=x;  
            p[ans].b=z; 
			p[ans].s=x*z;
            p[ans++].len=y;  
            p[ans].a=z;  
            p[ans].b=y;  
			p[ans].s=z*y;
            p[ans++].len=x;  
        }  
        sort(p+1,p+ans,comp);
		memset(dp,0,sizeof(dp));
		for(i=1;i<ans;i++)    //这么赋初值 ,就行了,,,
			dp[i]=p[i].len;
		for(i=1;i<ans;i++)
			for(j=1;j<i;j++)
				if((((p[i].a>p[j].a)&&(p[i].b>p[j].b))||((p[i].a>p[j].b)&&(p[i].b>p[j].a))))
				{
					if(dp[j]+p[i].len > dp[i])
						dp[i]=dp[j]+p[i].len;
				}
		int max=-1;
		for(i=1;i<ans;i++)
			if(dp[i]>max) max=dp[i];
        printf("Case %d: maximum height = %d\n",t,max);  
    }  
} 



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值