第八周 Week8-图和树的性质与应用(下)

A : 元音回文

问题描述
现在有一个长度为 nn 的字符串,都有小写字母组成。
现在所有元音字母都可以看作相同的字符
输出最长回文子串的长度

一个与自身的逆序相同的字符串即为回文串
比如 aba,aabbaa,asdffdsaaba,aabbaa,asdffdsa 都为回文串

输入格式
第一行一个整数 nn , 1\le n\le50001≤n≤5000,表示字符串长度
接下来一行表示字符串

输出格式
输出一行,一个数,代表答案

样例输入
10
aeioubaeio
样例输出
9
样例解释
所以元音都可以看作相同字符,所以回文串为 eioubaeioeioubaeio

#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
map<char,char>has;
char a[5010];
int n;
int getmax1(int k)
{
int ans=1;
int i=k-1;
int j=k+1;
while(i>=0&&j<n)
{
if(a[i]==a[j])
	{ans+=2;i--;j++;continue;}	 
break;
}
return ans;

}

int getmax2(int k)
{
int ans=0;
int i=k;
int j=k+1;
while(i>=0&&j<n)
{
if(a[i]==a[j])
	{ans+=2;i--;j++;continue;}
break;
}

return ans;
}

int main()
{
has.insert(make_pair('u','u'));
has.insert(make_pair('e','e'));
has.insert(make_pair('i','i'));
has.insert(make_pair('o','o'));
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
map<char,char>::iterator it;
it=has.find(a[i]);
if(it!=has.end())
	a[i]='a';
} 

int mmax=0;
for(int i=0;i<n;i++)
{
mmax=max(getmax1(i),mmax);
mmax=max(getmax2(i),mmax);
}
cout<<mmax<<endl;





}

在这里插入图片描述

B : 模测成绩单

问题描述
模测结束了,小 L 拿到了一些形如 A 比 B 得分高 的信息,现在小 L 想要输出一份成绩排名表,使得排名表满足得到的信息,并且学号小的尽可能排在前面。

输入格式
第一行有两个整数,n,mn,m 表示有 nn 个同学,第 ii 个同学学号为 ii ,有 mm 条信息。
接下来有 mm 行,每行有两个整数 A,BA,B ,表示学号为 AA 的同学得分比学号为 BB 的同学得分高。
1\le n,m\le 10^61≤n,m≤10
6

1\le A,B\le n1≤A,B≤n
数据保证有解

输出格式
输出一行 nn 个数,表示按照学号给出的排名。

样例输入
5 3
4 5
2 3
1 5
样例输出
1 2 3 4 5

#include <iostream>
#include <queue>

#define N 1000000

using std::priority_queue;

int point[N], nex[N], v[N], in[N];
int mark[N];
int tot = 0;

void add(int x, int y)
{
    tot++;
    nex[tot] = point[x];
    point[x] = tot;
    v[tot] = y;
    in[y]++;
}

int main()
{
    int n, m;
    priority_queue<int, std::vector<int>, std::greater<int> > q;
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++)
    {
        int x, y;
        scanf("%d %d", &x, &y);
        add(x, y);
    }
    for (int i = 1; i <= n; i++)
    {
        if (in[i] == 0)
        {
            q.push(i);
            mark[i] = 1;
        }
    }
    while (!q.empty())
    {
        int x = q.top();
        printf("%d ", x);
        q.pop();
        for (int i = point[x]; i; i = nex[i])
        {
            in[v[i]]--;
            if (in[v[i]] == 0 && !mark[v[i]])
            {
            mark[v[i]] = 1;
                q.push(v[i]);
            }
        }
    }
    printf("\n");
    return 0;
}

在这里插入图片描述

C : 种酸奶

问题描述
小 L 喜欢喝酸奶,春天来了,小 L 想把酸奶种在地里,等到来年春暖花开,就能长出好多好多酸奶了
有 nn 个坑,小 L 给坑都编上号,从 11 号到 nn 号,每个坑最多种一瓶酸奶。
但是有一些限制形如 k,a,b,ck,a,b,c 。
若 kk 等于 11 ,则第 aa 号坑到第 bb 号坑最多种 cc 瓶酸奶。
若 kk 等于 22 ,则第 aa 号坑到第 bb 号坑最少种 cc 瓶酸奶。
若 kk 等于 33 ,则第 aa 号坑到第 bb 号坑必须种少于 cc 瓶酸奶。
若 kk 等于 44 ,则第 aa 号坑到第 bb 号坑必须种多于 cc 瓶酸奶。
若 kk 等于 55 ,则第 aa 号坑到第 bb 号坑必须种等于 cc 瓶酸奶。

问小 L 最多种多少瓶酸奶

输入格式
第一行两个整数 n,mn,m ,表示有 nn 个坑,有 mm 条限制。
1\le n,m\le10001≤n,m≤1000
接下来 mm 行,每行四个整数 k,a,b,ck,a,b,c
1\le k\le 51≤k≤5 , 1\le a\le b\le n1≤a≤b≤n , |c|<=2000∣c∣<=2000

输出格式
输出一行,若有解则输出一个整数,表示答案
否则输出 impossible

样例输入
5 5
1 1 4 4
2 2 5 1
3 2 4 2
4 1 5 2
5 1 3 2
样例输出
3

#include <iostream>
#include <queue>

#define N 300000
#define INF 99999999

using std::pair;
using std::queue;
using std::make_pair;

int dis[N], v[N], point[N], nex[N], w[N];
int can[N], cnt[N];
int tot = 0;

void add(int x1, int x2, int wi)
{
    // x1 + w >= x2
    tot++;
    nex[tot] = point[x1];
    point[x1] = tot;
    v[tot] = x2;
    w[tot] = wi;
}

bool spfa(int s, int n)
{
    queue<int> q;
    for (int i = 1; i <= n; i++)
    {
        dis[i] = INF;
        can[i] = 0;
    }
    dis[s] = 0;
    can[s] = 1;
    q.push(s);
    while (!q.empty())
    {
        int x = q.front();
        q.pop();
        for (int i = point[x]; i; i = nex[i])
        {
            if (dis[v[i]] > dis[x] + w[i])
            {
                dis[v[i]] = dis[x] + w[i];
                cnt[v[i]] = cnt[x] + 1;
                if (cnt[v[i]] >= n)
                {
                    return false;
                }
                if (!can[v[i]])
                {
                    can[v[i]] = 1;
                    q.push(v[i]);
                }
            }
        }
        can[x] = 0;
    }
    return true;
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++)
    {
        int k, x, y, wi;
        scanf("%d %d %d %d", &k, &x, &y, &wi);
        if (k == 1)
            add(x, y + 1, wi);
        if (k == 2)
            add(y + 1, x, -wi);
        if (k == 3)
            add(x, y + 1, wi - 1);
        if (k == 4)
            add(y + 1, x, -wi - 1);
        if (k == 5)
        {
            add(x, y + 1, wi);
            add(y + 1, x, -wi);
        }
    }
    for (int i = 1; i < n + 1; i++)
    {
        add(i, i + 1, 1);
        add(i + 1, i, 0);
    }
    bool getted = spfa(1, n + 1);
    if (getted)
        printf("%d\n", dis[n + 1]);
    else
        printf("impossible\n");
    return 0;
}

在这里插入图片描述

D : 信息传递

问题描述
有 nn 个人,每个人都有一个编号,从 11 到 nn 。
如果 AA 得知一个消息,那么他一定会告诉 BB 。
问最少把消息告诉几个人,能让所有人得知这个消息。

输入格式
第一行两个整数 n,mn,m , 1\le n,m\le 10^61≤n,m≤10
6
,表示有 nn 个人
接下来 mm 行,每行给出一个关系形如 A,BA,B ,表示如果 AA 得知一个消息,那么他一定会告诉 BB 。

输出格式
输出一行,一个数,代表答案

样例输入
10 10
1 3
2 4
4 5
2 8
5 2
5 9
6 8
9 2
10 5
5 8
样例输出
4
样例解释
只需要告诉 1,6,7,101,6,7,10 四个人即可

#include <iostream>

#define N 9999999

int l_v[N], l_point[N], l_nex[N];
int l_tot;
int f1[N];
int f1i = 0, f2i = 0;
int f2[N];
int mrk1[N];
int mrk2[N];
int x_v[N];
int x_point[N];
int x_nex[N];
int x_tot;
int ine[N];

void add(int x, int y)
{
    l_tot++;
    l_nex[l_tot] = l_point[x];
    l_point[x] = l_tot;
    l_v[l_tot] = y;
}

void addx(int x, int y)
{
    x_tot++;
    x_nex[x_tot] = x_point[x];
    x_point[x] = x_tot;
    x_v[x_tot] = y;
}

void dfs1(int v)
{
    mrk1[v] = 1;
    for (int i = l_point[v]; i; i = l_nex[i])
    {
        if (!mrk1[l_v[i]])
        {
            dfs1(l_v[i]);
        }
    }
    f1[++f1i] = v;
}

void dfs2(int v)
{
    f2[v] = f2i;
    for (int i = x_point[v]; i; i = x_nex[i])
    {
        if (!f2[x_v[i]])
        {
            dfs2(x_v[i]);
        }
    }
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int x, y;
        scanf("%d %d", &x, &y);
        add(x, y);
        addx(y, x);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!mrk1[i]) dfs1(i);
    }
    for (int i = n; i > 0; i--)
    {
        if (!f2[f1[i]])
        {
            f2i++;
            dfs2(f1[i]);
            // printf("%d- %d\n", f2i, f1[i]);
        }
    }
    for (int i = 1; i <= n; i++)
    {
        // printf("%d  %d\n", f1[i], f2[i]);
        for (int p = l_point[i]; p; p = l_nex[p])
        {
            if (f2[i] != f2[l_v[p]])
            {
                ine[f2[l_v[p]]]++;
            }
        }
    }
    // printf("\n");

    int count = 0;
    for (int i = 1; i <= f2i; i++)
    {
        if (ine[i] == 0) count++;
    }

    printf("%d\n", count);
    return 0;
}

在这里插入图片描述

思路

第一个题在力扣网站上看见过,当时就不会,和这个差不多的用的双指针做的。
好写一点的基础做法用到这个:
链接

第二个需要队列:定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式。

当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。

种酸奶:
在这里插入图片描述
先要学会这个
最后一题和例题一样在这里插入图片描述
在这里插入图片描述
后面还有个强连通分量的知识
在这里插入图片描述
下周题有的话再学学这块。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值