Week11-练习
第一题
评析:其实就是个线性DP,包了一层壳,但是这输入是真变态。
#include<bits/stdc++.h>
using namespace std;
int n,f[105][105];
int main(){
scanf("%d",&n);
int ans=1e8;
for(int i=1; i<=n; i++){
int k; scanf("%d",&k);
for(int j=1; j<=k; j++){
int x,y;
f[i][j]=1e8;
while(scanf("%d",&x)){
if(x==0) break;
scanf("%d",&y);
f[i][j]=min(f[i][j], f[i-1][x]+y);//线性DP模板
}
}
if(i==n){
for(int j=1; j<=k; j++)
ans=min(ans,f[n][j]);//选取答案
}
}
printf("%d",ans);
return 0;
}
第二题
评析:计数DP,代码看似短,实际非常难想。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll f[505][505];
int main(){
f[0][0]=1;
scanf("%d",&n);
for(int i=0; i<=n; i++){
for(int j=0; j<=i; j++){
for(int k=j+1; i+k<=n; k++)
f[i+k][k]+=f[i][j];//转移方程
}
}
ll ans=0;
for(int i=1; i<=n; i++)
ans+=f[n][i];
printf("%lld",ans-1);//注意题目条件,次数一定要大于1,所以在此处减1
return 0;
}
第三题
评析:思路是砝码两边都可以放,所以可以加也可以减,我们正反向遍历两遍就可以解决这个问题。
#include<bits/stdc++.h>
using namespace std;
int n,a[105],f[100005],ans,sum;
int main()
{
cin>>n;
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i]; //先把总数算出来
}
f[0]=1;
for (int i=1;i<=n;i++)
for (int j=sum;j>=a[i];j--)
{
if (f[j-a[i]]==1 && f[j]!=1)
{
ans++;
f[j]=1;
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=sum-a[i];j++)
{
if (f[j+a[i]]==1 && f[j]==0)
{
ans++;
f[j]=1;
}
}
printf("%d",ans);
return 0;
}
第四题
评析:这题较简单,把点两两枚举一下,判断一下是否越界,取最大即可(事实上开始没注意到O2复杂度,直接就枚举两个点了,运气了)
#include<bits/stdc++.h>
using namespace std;
struct node
{
int x,y;
}a[3005];
int n,ans,f[5005][5005];
int main()
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i].x>>a[i].y;
f[a[i].x][a[i].y]=1;//标记
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
int u=a[i].x-a[j].x;
int v=a[i].y-a[j].y;
if (a[i].x-v<1 || a[i].x-v>5000 || a[j].x-v<1 || a[j].x-v>5000 || a[i].y+u<1 || a[i].y+u>5000 || a[j].y+u<1 || a[j].y+u>5000) continue;//判断是否越界,其实还是先表示一下比较好,否则这行实在太长
if (f[a[i].x-v][a[i].y+u]==1 && f[a[j].x-v][a[j].y+u]==1) ans=max(ans,u*u+v*v);//取最大
}
cout<<ans;
return 0;
}
第五题
评析:Floyd+二分,想到了用Floyd,但没想到用二分实操,看了题解才会。
#include<bits/stdc++.h>
using namespace std;
long long n,q,ans=1e9,a[105][105],b[105][105],dis[105][105],down[105];
bool check(long long d)
{
long long temp=0,op=d-n*(d/n);
for(int i=1;i<=n;i++)
{
down[i]=d/n+bool(i<=op);
dis[i][i]=0;
}//初始化
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=max(a[i][j]-down[i]-down[j],b[i][j]);
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);//Floyd
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
temp+=dis[i][j];
if(temp<=q) return true;
else return false;//判断
}
int main()
{
cin>>n>>q;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
cin>>a[i][j];
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
cin>>b[i][j];
long long l=0,r=1e9,mid;
while(l<r)
{
mid=(l+r)/2;
if (check(mid))
{
ans=min(ans,mid);
r=mid;
}
else l=mid+1;
}//二分
if (l==1e9) cout<<"-1"<<endl;
else cout<<ans<<endl;
return 0;
}