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;
}