week 11 巩固

1.汤姆斯的天堂梦

这道题要用到动态规划的知识 ,状态转移方程为f[i,j]=min{f[i-1,j]+L};

代码:

#include <bits/stdc++.h>
using namespace std;
int n, a, b, c, f[2000][2000]={0};
int main()
{
	cin>>n;//n级 
	for(int i = 1; i <= n; i ++)
	{
		cin>>a;//i级星球个数 
		for(int j = 1; j <= a; j ++)//枚举每个星球 
		{
			f[i][j] = 0x7ffffff;//初始化
			cin>>b;//i-1级的b号星球到i级j号星球 
			while(b != 0)//终止条件 
			{
				cin>>c;
				f[i][j] = std::min(f[i - 1][b] + c, f[i][j]);
				cin>>b;
			}
		}
	}
	int minn = 0x7ffffff;
	for(int i = 1; i <= a; i ++)
	minn = std::min(f[n][i], minn);//求最小
	cout<<minn;
	return 0;
}

2.跑步

题意为次数大于一,并且圈数越来越多,总共n圈。这道题用dfs和bfs都会运行超时,只有用动态规划不会超时。

代码:

#include<bits/stdc++.h>
using namespace std;
long long n,ans[501]; 
int main(){
    cin>>n;
    ans[0]=1;
    for (int i=1;i<=n;i++){
    	for (int j=n;j>=i;j--){
    		ans[j]+=ans[j-i];
		}
	}
	cout<<ans[n]-1<<endl;
    return 0;
}

3.砝码称重

 这是一道很经典的01背包问题,其状态转移方程需要满足:不放砝码,即上面的方案都能用;只放现在的那个;在对于第i个砝码的选择中选择左边,即砝码重量加现在的天平上的重量等于原来的重量;在对于第i个砝码的选择中选择右边,即砝码重量减现在的天平上的重量等于原来的重量。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,ans,sum,w[101],dp[101][100001];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>w[i];
        sum+=w[i];
    }
    for(int i=1;i<=n;i++)
    {
		for(int j=sum;j;j--)
		{
            if(j==w[i])dp[i][j]=1;
            else if(dp[i-1][j])dp[i][j]=1;
			else if(dp[i-1][j+w[i]])dp[i][j]=1;
            else if(dp[i-1][abs(j-w[i])])dp[i][j]=1;
        }
	}  
    for(int i=1;i<=sum;i++)if(dp[n][i])ans++;
    cout<<ans<<endl;
    return 0;
}

4.遗址

这道题思路首先是要找到正方形的四个顶点,因为时间复杂度的关系,最多只能通过枚举两个点来确定其他点的位置。再通过勾股定理就可以把这道题解出来了。

代码:

#include <bits/stdc++.h>
#define ll int 
#define E 3007
using namespace std ;
ll n , ans ;
ll x[E] , y[E] ;
bool mmp[E << 1][E << 1] ;
ll read() 
{ 
    ll s = 0 ; char ch ; 
    while(!isdigit(ch = getchar())) ;
    for(s = ch - '0' ; isdigit(ch = getchar()) ; (s *= 10 ) += ch - '0') ;
    return s ;
}
bool pd(ll uu , ll vv)   // 判断 当前点 有没有出界
{
    if(uu < 0 || uu > 5000)return 0 ;
    if(vv < 0 || vv > 5000)return 0 ;
    return 1 ;
}
ll check(ll xx , ll yy , ll zx , ll zy ) // 用我们在图中找到的规律寻找正方形
{
    ll cx = xx - zx , cy = yy - zy ;
    if( pd(xx + cy , yy - cx) && mmp[xx + cy][yy - cx] )   // 其实mmp 也可以写在pd函数里,判断当前坐标是否存在 点
        if( pd(zx + cy , zy - cx) && mmp[zx + cy][zy - cx] )
            return cx * cx + cy * cy ;           // 如果在第一个时就成立 , 直接返回就好 , 因为就算第二个也成立,面积也是一样的
    if( pd(xx - cy , yy + cx) && mmp[xx - cy][yy + cx] )
        if( pd(zx - cy , zy + cx) && mmp[zx - cy][zy + cx] )
            return cx * cx + cy * cy ;           // 面积计算方法有多种证明方法 , 比较直观的就是 sqrt(cx*cx + cy*cy)^2 ;
    return 0 ;            // 没找到 , 返回零
}
int main()
{
    n = read() ;
    for(int i = 1;i <= n; i ++)
    {
        x[i] = read() ; y[i] = read() ;
        mmp[x[i]][y[i]] = 1 ;
    }
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1; j <= i ; j ++ )
            ans = max( ans , check(x[i] , y[i] , x[j] , y[j] ) ) ;    // 对答案求最大值
    cout<< ans <<endl;
    return 0 ;
}

5.环境治理

这题可以用Floyd 算法做。发现天数越多,任意两点之间的最短距离的和越小,所以可以二分答案。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=110;

LL g[N][N];
LL m[N][N];
LL f[N][N];
LL n,q;
LL floyd()
{
	LL a=0;
	for (int k = 1; k <= n; k ++ )
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
                f[i][j] = min(f[i][j], f[i][k] + f[k][j]);

    for(int i=1;i<=n;++i)
    	for(int j=1;j<=n;++j)
    		a+=f[i][j];
    return a;
}
//改善X天
bool check(LL x){
	memcpy(f,g,sizeof(g));
	LL h=x/n;
	LL s=x%n;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(i==j) continue;
			if(i<=s) f[i][j]=max(m[i][j],f[i][j]-h-1);
			else f[i][j]=max(m[i][j],f[i][j]-h);
			//f[j][i]=f[i][j];
		}
	}
	return floyd()<=q;
}
void solve()
{
	cin>>n>>q;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			cin>>g[i][j];
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			cin>>m[i][j];
			f[i][j]=m[i][j];
		}
	}
	if(floyd()>q){
		cout<<-1<<endl;
		return;
	}
	LL l=0,r=1000000000;
	while(l<r){
		int mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<r<<endl;
}
int main() 
{
	solve();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无用夜宵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值