2022.3.11

蓝书

AcWing 112. 雷达设备

思路:对于确定每座岛屿在x轴上能被雷达监视的左右区间,然后初始化位置pos,每次判断一下,如果pos小于当前岛屿的左区间,那么需要新加一个雷达,并更新pos为该岛屿的又区间,如果pos大于的话说明可以管辖,我们让pos=min(r,pos)。目的是将i的位置尽量往后放。
注意左右区间得是double才行,不然会cnt数量最后会变多。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<double,double> pdd;
const int N=1e5+10,INF=1e8;
pdd land[N];
int main()
{
    int n;
    double d;
    scanf("%d%lf", &n, &d);
    for (int i = 1; i <= n;i++)
    {
        double x, y;
        scanf("%lf%lf", &x, &y);
        if(y>d)
        {
            printf("-1");
            return 0;
        }
        land[i].first = x - sqrt((d * d) - (y * y));
        land[i].second= x + sqrt((d * d) - (y * y));
    }
    sort(land + 1, land + 1 + n);
    double pos = -INF;
    int cnt = 0;
    for (int i = 1; i <= n;i++)
    {
        double l = land[i].first, r = land[i].second;
        if(l>pos+1e-6)
        {
            cnt++;
            pos = r;
        }
        else
            pos = min(r, pos);
    }
    printf("%d\n", cnt);
    return 0;
}

AcWing 114. 国王游戏

思路:需要对大臣的左右手的数的乘积进行贪心,然后对大臣的左右手的乘积进行从小到大排序,最后才能得到最优解。其中利用到了微扰证明,即证明在整体的情况下,减少逆序对的个数不会造成整体局面变差,增加逆序对的个数则不会使整体局面变好。那么当序列变成有序的时候,所得到的就是最优解。
贪心思路还记得但一开始写的时候忘了要用大数乘法和除法,太久没写了导致又wa了几次。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
pii a[N];
vector<int> mul(vector<int> a,int b)
{
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size()||t;i++)
    {
        if(i<a.size())
            t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }
    return c;
}
vector<int> div(vector<int> a,int b)
{
    vector<int> c;
    int t = 0;
    bool ok = 1;
    for (int i = a.size() - 1; i >= 0;i--)
    {
        t = t * 10 + a[i];
        int x = t / b;
        if(!ok||x)
        {
            ok = 0;
            c.push_back(x);
        }
        t %= b;
    }
    reverse(c.begin(), c.end());
    return c;
}
vector<int> cmp(vector<int > a,vector<int > b)
{
    return a.size() > b.size() ? a : b;
    return (vector<int>(a.rbegin(), a.rend())) > (vector<int>(b.rbegin(), b.rend())) ? a : b;
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i <= n;i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        a[i] = {x * y, x};
    }
    sort(a + 1, a + 1 + n);
    vector<int> mult(1, 1);
    vector<int> ans(1, 0);
    for (int i = 0; i <=n ;i++)
    {
        if(i)
            ans = cmp(ans, div(mult, a[i].first / a[i].second));
        mult = mul(mult, a[i].second);
    }
    for(int i=ans.size()-1;i>=0;i--)
    {
        printf("%d", ans[i]);
    }
        return 0;
}

AcWing 115. 给树染色

思路:因为之前栽过坑所以这次想起不能像第一次做那样每次选择当前权值最大的点去合并,可以举个反例,一个权值很小的点下边有很权值巨大的点,而另一个权值较大的点没有子节点。
因此我们不能一个一个的判断。但是我们可以根据题意发现这样一个性质,对于一个点如果它是除了根节点之外权值最大的点,那么它因在它的根节点被染色后立即染色。那么实际上这种连续的操作把这两个点绑在了一起就相当于一个点,对于染色,假设三个点x,y,z,当且仅当x和y的平均值大于z的时候可以先染x,y。我们可以通过不断地合并的点最终将整个树合并成一个点,并在合并的时候计算染色的花费。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
int n, root,ans;
struct tree
{
    int val, sz, fa;
    double avg;
}point[N];
int find()
{
    double res = 0;
    int ans = 0;
    for (int i = 1;i<=n;i++)
    {
        if(i!=root&&point[i].avg>res)
        {
            res = point[i].avg;
            ans = i;
        }
    }
    return ans;
}
int main()
{
    scanf("%d%d", &n, &root);
    for (int i = 1; i <= n;i++)
    {
        int val;
        scanf("%d", &val);
        point[i].avg = point[i].val = val;
        ans += val;
        point[i].sz = 1;
    }
    for (int i = 1; i <= n - 1;i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        point[b].fa = a;
    }
    for (int i = 1; i <= n - 1;i++)
    {
        int x = find(), fa = point[x].fa;
        ans += point[x].val * point[fa].sz;
        for (int j = 1; j <= n;j++)
        {
            if(point[j].fa==x)
                point[j].fa = fa;
        }
        point[x].avg = 0;
        point[fa].sz += point[x].sz;
        point[fa].val += point[x].val;
        point[fa].avg = (double)point[fa].val / point[fa].sz;
    }
    printf("%d", ans);
    return 0;
}

AcWing 178. 第K短路

思路:实际上第k短路是由最短路推过来的,我们知道在dijskra里当某个点第一次被访问的时候说明求出了到这个点的最短路,那么由数学归纳法,当某个点第k次被访问的时候求出来的就是第k短路,为了有目的的找到第k短路我们需要引入估价函数,即F(x)=G+H。其中G为起点到当前点的实际距离,H为当前点到终点的实际距离。并且f(X)<=g(x),否则可以证明最终取出的答案是错误的,证明见蓝书。那么当前点到终点的最短路实际上反过来就是终点到当前点的最短路。我们先预处理终点到各个节点的最短路,同时将F,即起点到当前点的实际距离加上当前点到终点的实际距离从小到大排序,每次取出F最小的点,如果vis[x]次数小于k的话就更新点,如果等于大于k的话就跳过,当终点的访问次数等于k时,得到的就是从起点到终点的第k短路。
坑点:一开始样例过了提交wa了一发,怎么也想不到哪错了,看完题解发现需要特判当起点等于终点的情况,还有就是一开始建结构体的时候搞错了,只建了f和x,即当前点到终点的距离,当没有建起点到当前点的距离。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e4+10,INF=1e8;
int n, m, s, t, k,cnt1,cnt2,h1[N],h2[N];
int vis[N],dis[N];
struct stu
{
    int f, dis, x;
    bool operator < (stu a) const
    {
        return dis + f > a.dis + a.f;
    }
};
struct node
{
    int ne,to,w;
} edge1[N*2],edge2[N*2];
void add1(int a,int b,int c)
{
    edge1[++cnt1].to = b;
    edge1[cnt1].w = c;
    edge1[cnt1].ne = h1[a];
    h1[a] = cnt1;
}
void add2(int a,int b,int c)
{
    edge2[++cnt2].to = b;
    edge2[cnt2].w = c;
    edge2[cnt2].ne = h2[a];
    h2[a] = cnt2;
}
void dijkstra()
{
    priority_queue<pii, vector<pii>, greater<pii>> que;
    memset(dis, 0x3f, sizeof dis);
    dis[t] = 0;
    que.push({0, t});
    while(que.size())
    {
        auto t = que.top();
        que.pop();
        int dist = t.first, id = t.second;
        if(vis[id])
            continue;
        vis[id] = 1;
        for (int i = h2[id];i;i=edge2[i].ne)
        {
            int j = edge2[i].to;
            if(dis[j]>dis[id]+edge2[i].w)
            {
                dis[j] = dis[id] + edge2[i].w;
                que.push({dis[j], j});
            }
        }
    }
}
int astar()
{
    memset(vis, 0, sizeof vis);
    priority_queue<stu> que;
    que.push({dis[s],0,s});
    while(que.size())
    {
        auto tt = que.top();
        que.pop();
        int f = tt.f, dist=tt.dis ,x= tt.x;
        vis[x]++;
        if(vis[t]==k)
            return dist;
         if(vis[x]>k)
            continue;
        for (int i = h1[x]; i;i=edge1[i].ne)
        {
            int j = edge1[i].to;
            if(vis[j]<k)
            {
                que.push({dis[j] + edge1[i].w + dist,dist+edge1[i].w, j});
            }
        }
    }
    return -1;
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m;i++)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add1(a, b, c);
        add2(b, a, c);
    }
    scanf("%d%d%d", &s, &t, &k);
    if(s==t) k++;
    dijkstra();
    printf("%d", astar());
    return 0;
}
posted @ 2022-03-11 11:55  menitrust  阅读(20)  评论(0编辑  收藏  举报