22/7/8

本文探讨了两道计算机科学中的最优化问题。第一题是关于最优贸易的动态规划解决方案,利用SPFA算法求解最小买入成本和最大卖出收益。第二题是AlmostEqual问题,要求构造一个数字环,使得环内每n个数之和的差不超过1。通过分析得出,只有当n为奇数时,这样的环才可能存在,并给出了构造序列的规律。
摘要由CSDN通过智能技术生成

1,acwing 341.最优贸易;2,cf  Almost Equal;


1,最优贸易;

思路:采取dp的思想,枚举分界点,求1到分界点的最小买入价格和分界点到n的最大卖出价格;

 注意dijkstra和spfa的区别:

dijkstra算法里,一旦该点确定最小值后,就不会在更新该点了,但是本题中当前最小值不一定是最终最小值,所以用spfa;

求最大值就是建反边,再来一遍spfa;

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for(register int i=(a);i<(n);++i) 
#define rep2(i,a,n) for(register int i=(a);i<=(n);++i) 
#define per1(i,n,a) for(register int i=(n);i>(a);i--) 
#define per2(i,n,a) for(register int i=(n);i>=(a);i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pro_q priority_queue
#define pb push_back
#define pf push_front
#define endl "\n"
#define lowbit(m) ((-m)&(m))
#define YES cout<<"YES\n"
#define NO cout<<"NO\n"
#define Yes cout<<"Yes\n"
#define No cout<<"No\n"
#define yes cout<<"yes\n"
#define no cout<<"no\n"
#define yi first
#define er second
#define INF 0x3f3f3f3f
#define tulun() int e[N],ne[N],h[N],w[N],idx;
#define add2(a,b) e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define add3(a,b,c) w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define moreT int T;cin>>T;while(T--)solve();
using namespace std;
typedef long long LL;
typedef double dob;
const int N=2e6+10;
tulun();
int n,m;
int price[N],rh[N],dmin[N],dmax[N],st[N];
void add(int *h,int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void spfa(int *d,int start,int *h,bool flag)
{
    queue<int>q;
    memset(st,0,st);
    if(flag)memset(d,0x3f,dmin);
    q.push(start);
    d[start]=price[start];
    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=0;
        for(int i=h[t];~i;i=ne[i])
        {
            int j=e[i];
            if(flag&&d[j]>min(d[t],price[j])||!flag&&d[j]<max(d[t],price[j]))
            {
                if(flag)d[j]=min(d[t],price[j]);
                else d[j]=max(d[t],price[j]);
                if(!st[j])
                {
                    st[j]=1;
                    q.push(j);
                }
            }
        }
    }

}
signed main()
{
    quick_cin();
    cin>>n>>m;
    memset(h,-1,h);
    memset(rh,-1,rh);
    rep2(i,1,n)cin>>price[i];
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(h,a,b),add(rh,b,a);
        if(c==2)add(h,b,a),add(rh,a,b);
    }
    spfa(dmin,1,h,1);
    spfa(dmax,n,rh,0);
    int ans=0;
    rep2(i,1,n)ans=max(ans,dmax[i]-dmin[i]);
    cout<<ans;
    return 0;
}

2, Almost Equal;

题意:给你数字n,要求创造一个环包含1~2n,且 在环内每取n个数的和,这些和之间的差不能超过1,如果存在环输出,否则NO;

思路:先看样例模拟,

n=3,1,4,5,2,3,6;

 很巧妙的发现,从1,4,5开始,后面类似滑动窗口,每进来一个数,就出去一个数,且进出元素的差不超过1;

如果想要和之间差不超1,就只能让按照和+1,-1,+1,-1的顺序来;

拿1,4,5举例,

2进来,1出去,和+1;

3进来,4出去,和-1;

6进来,5出去,和+1;

1进来,2出去,和-1;

4进来,3出去,和+1;

5进来,6出去,和-1,就又是1,4,5了;完美;

所以很容易想到n=偶数是不可行的,

因为n是偶数,就说明+1,-1,+1,-1是偶数对,而折返时取得时相反的序列;

就拿n=4,正序列可以取到,+1,-1,+1,-1,然后开始环取,相反,-1,+1,-1,+1;

总的就是+1,-1,+1,-1,-1,+1,-1,+1;两个-1连续出现!!所以和的差就超过1了!!;

再然后还能发现取得序列的规律;

n=3,1,4,5,2,3,6

n=4,1,4,5,8,2,3,6,7;(供参考找规律)

n=5,1,4,5,8,9,2,3,6,7,10;

n=6,1,4,5,8,9,12,2,3,6,7,10,11;

n每次增长,都只是在原来的序列上变化;

因为1~2n的排列,所以只看前半部分,后半部分因为从小到大,可以直接放进来;

1,4,5

1,4,5,8

1,4,5,8,9

1,4,5,8,9,12

此序列的增长规律就是,第一个元素是1,此后下标是偶数,a[i]=a[i-1]+3,奇数,a[i]=a[i-1]+1;

借此获得前半部分,后半部分直接放即可;

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for(register int i=(a);i<(n);++i) 
#define rep2(i,a,n) for(register int i=(a);i<=(n);++i) 
#define per1(i,n,a) for(register int i=(n);i>(a);i--) 
#define per2(i,n,a) for(register int i=(n);i>=(a);i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pro_q priority_queue
#define pb push_back
#define pf push_front
#define endl "\n"
#define lowbit(m) ((-m)&(m))
#define YES cout<<"YES\n"
#define NO cout<<"NO\n"
#define Yes cout<<"Yes\n"
#define No cout<<"No\n"
#define yes cout<<"yes\n"
#define no cout<<"no\n"
#define yi first
#define er second
#define INF 0x3f3f3f3f
#define tulun() int e[N],ne[N],h[N],w[N],idx;
#define add2(a,b) e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define add3(a,b,c) w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define moreT int T;cin>>T;while(T--)solve();
using namespace std;
typedef long long LL;
typedef double dob;
const int N=2e6+10;
int n;
int a[N];
int hs[N];
vector<int>ans;

signed main()
{
    quick_cin();
    cin>>n;
    if((n&1)==0)
    {
        NO;
        return 0;
    }
    a[1]=1;
    hs[1]=1;
    ans.pb(1);
    rep2(i,2,n)
    {
        if(i&1)a[i]=a[i-1]+1;
        else a[i]=a[i-1]+3;
        hs[a[i]]=1;
        ans.pb(a[i]);
    }
    rep2(i,1,n*2)
    {
        if(!hs[i])ans.pb(i);
    }
    YES;
    rep1(i,0,ans.size())cout<<ans[i]<<" ";
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Dull丶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值