18寒假第一测

Posted Ed_Sheeran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了18寒假第一测相关的知识,希望对你有一定的参考价值。

猪猪的想法
输入文件:thought.in
输出文件:thought.out
时间限制:1 second
空间限制:128 MB
题目描述
狗蛋养了许多只可爱的猪猪,这些猪猪她萌都有一些奇怪的想法:比如说猪猪喜欢猪猪,猪猪之间的喜欢是一
个很有趣的事情——喜欢是可以传递的,例如猪猪喜欢猪猪,猪猪喜欢猪猪,那么可以说猪猪喜欢猪猪
。有意思的一点是,她萌不喜欢自恋的猪猪,一旦出现了自恋的猪猪,那么极有可能的是这个团体出现危险。现在
给你只猪猪对单方面的关系,请问这个只猪猪组成的团体是否危险呢?是输出Yes ,否输出No 。
输入格式
题目包含多组数据。
第一行一个数,表示数据组数。
对于每一组数据:
第一行两个正整数,表示有只猪猪和个单向关系。
接下来行,每一行两个数表示的单向关系。
输出格式
共行,每一行一个字母,表示结果。
样例
样例输入

2
2 2
1 2
2 1
2 1
1 2


样例输出

No
Yes

数据范围
n <=10^6 , m <= n*(n-1)/2 ;

题解:用拓扑看有没有环就好了,不过我用的tarjian,不过此题的一个点 指向自己的情况要注意

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 100000 + 5;
int n, m, top, t[maxn], dfn[maxn], low[maxn], cnt, idx, scccnt;
bool ins[maxn];
vector <int> G[maxn], scc[maxn]; 

void tarjian(int u){
    dfn[u] = low[u] = ++idx;
    t[++top] = u;
    ins[u] = 1;
    
    for(int i = 0; i < G[u].size(); i++){
        int v = G[u][i];
        if(!dfn[v]){
            tarjian(v);
            low[u] = min(low[v], low[u]);
        }
        else if(ins[v])low[u] = min(low[u], dfn[v]);
    }
    
    if(dfn[u] == low[u]){
        int x = dfn[u];
        scccnt++;
        while(low[t[top]] == x){
            scc[scccnt].push_back(t[top]);
            ins[t[top--]] = 0;
        }
    }
}


int main(){
    freopen("thought.in","r",stdin);
    freopen("thought.out","w",stdout);
    int Q;
    scanf("%d",&Q);
    while(Q--){
        memset(t, 0, sizeof(t));
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(ins, 0, sizeof(ins));
        top = idx = scccnt = cnt = 0;
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n + 1; i++)
            G[i].clear(), scc[i].clear();
        for(int i = 1; i <= m; i++){
            int u, v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
        }        
        for(int i = 1; i <= n; i++)
            if(!dfn[i])tarjian(i);
        for(int i = 1; i <= scccnt; i++){
            if(scc[i].size() != 1)cnt++;
        }
        if(cnt)cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    
    return 0;
}

 

 


最长的路径
输入文件:dag.in
输出文件:dag.out
时间限制:1 second
空间限制:128 MB
题目描述
给定一张个点条边的有向无环图,每个点有点权,问从出发,路径最长是多少。
此处路径长度的定义为路径上的经过的点的点权和(包括起点和终点)。
输入格式
第一行包含三个数。
接下来一行个数,第个数表示的点权。
接下来行,每一行两个数表示的一条单向边。
输出格式
输出最长路径的长度。
样例
样例输入
样例输出
数据范围
n <=10^5 , m <= n*(n-1)/2 ;
5 5
1 2 3 4 5
1 2
2 3
3 4
4 5
5 1
15

题解:SPFA,用dijsktra要存负权,不能跑最大路

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<queue>
#include<cstring>
#define maxn 1000000 +5
using namespace std;
int n, m, S;
struct edge{
    int to,co;
};
vector <edge> G[maxn];
int dis[maxn], w[maxn], ans;
bool inq[maxn];
queue <int> Q;

void SPFA(int s){
    dis[s] = w[s];
    inq[s] = 1;
    Q.push(s);
    
    while(!Q.empty()){
        int u = Q.front();
        Q.pop();
        inq[u] = 0;
        
        for(int i = 0; i < G[u].size(); i++){
            edge &e = G[u][i];
            if(dis[e.to] < dis[u] + e.co){
                dis[e.to] = dis[u] + e.co;
                if(!inq[e.to]){
                    Q.push(e.to);
                    inq[e.to] = 1;
                }
            }
        }
    }
    
}
int main(){
    freopen("dag.in","r",stdin);
    freopen("dag.out","w",stdout);
    cin>>n>>m>>S;
    for(int i = 1; i <= n; i++)
        scanf("%d",&w[i]);
    for(int i = 1; i <= m; i++){
        int u, v;
        scanf("%d%d",&u,&v);
        G[u].push_back((edge){v,w[v]});
    }
    SPFA(S);
    for(int i = 1; i <= n; i++)
        ans = max(ans, dis[i]);
    cout<<ans<<endl;
}

 

美丽的有向图
输入文件:beauty.in
输出文件:beauty.out
时间限制:1 second
空间限制:128 MB
题目描述
定义一张有向图是美丽的,当且仅当任意选出两点:要么可以到,要么可以到.
给定一张个点条边的有向图,判断是否是美的。如果是,输出I am beautiful! ,否则输出Go away Anna.
输入格式
题目包含多组数据。
第一行一个数,表示数据组数。
对于每一组数据:
第一行两个正整数,表示有只猪猪和个单向关系。
接下来行,每一行两个数表示的单向关系。
输出格式
共行,每一行一个字符串,表示结果。
样例
样例输入

2

3 3
1 2
2 3
3 1
5 5
1 2
2 3
2 4
3 5
4 5

样例输出
I am beautiful!
Go away Anna.

数据范围
n <=10^5 , m <= n*(n-1)/2 ;

题解:先tarjian缩点,拓扑时有出度为2的点就不行了;缩点有点问题,就贴一个标答

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200005;
int dfn[maxn];//dfs顺序
int low[maxn];
int index1;//记录时间的标号
bool state[maxn];//是否在栈里.
stack<int>s;
vector<int>G[maxn];
vector<int>g[maxn];
int cnt[maxn];
int num[maxn], du[maxn];//num数组不一定要,各个强连通分量包含点的个数,数组编号1~cnt
int scc,flag;//scc为强连通分量的个数
int vis[maxn];
void init()
{
    scc = 0,flag=0;
    memset(du, 0, sizeof(du));
    memset(state, false, sizeof(state));
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(cnt, 0, sizeof(cnt));
    memset(vis, false, sizeof(vis));
    memset(num, 0, sizeof(num));
    while(!s.empty())
        s.pop();
    for(int i = 0; i < maxn; i++)
    {
        G[i].clear();
        g[i].clear();
    }
}
void tarjan(int u)//tarjan 处理强连通分量。
{
    dfn[u] = low[u] = ++index1;
    s.push(u);
    state[u] = true;
    vis[u] = true;
    for(int i = 0; i < G[u].size(); i++)
    {
        int w = G[u][i];
        if(!vis[w])
        {
            tarjan(w);
            low[u] = min(low[w], low[u]);
        }
        else if(state[w])
        {
            low[u] = min(low[u], dfn[w]);
        }
    }
    if(low[u] == dfn[u])
    {
        scc++;
        for(;;)
        {
            int x = s.top();
            s.pop();
            cnt[x] = scc;//标记v点属于哪个强连通分量
            num[scc]++;//记录这个强连通分量有多少个点组成
            state[x] = false;
            if(x == u)break;
        }
    }
}    queue<int>q;
void topsort()
{
    while (q.size()) q.pop();
    int sizz=0;
    for(int i=1;i<=scc;i++)
    {
        if(!du[i])
        {
            sizz++;
            q.push(i);
        }
    }
    if(sizz>=2) flag=1;//如果刚缩点后就有两个以上度为0的坑定不可以啊
    while(!q.empty()&&!flag)//拓扑找出度为2的点 
    {
        int u=q.front();
        q.pop();
        int siz=0;
        for(int i=0;i<g[u].size()&&!flag;i++)
        {
            int to=g[u][i];
            du[to]--;
            if(du[to]==0)
            {
                siz++;
                q.push(to);
            }
            
        }
        if(siz>=2) flag=1;
    }
}
int main()
{
//    freopen ( "beauty8.in", "r", stdin ) ;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
        }
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
            {
                tarjan(i);
            }
        }
        for(int i=1;i<=n;i++)//新建图
        {
            int u=cnt[i];
            for(int j=0;j<G[i].size();j++)
            {
                int v=cnt[G[i][j]];
                if(u!=v)
                {
                    g[u].push_back(v);
                    du[v]++;//入度
                }
            }
        }
        topsort();
        puts ( flag ? "Go away Anna." : "I am beautiful!" ) ;
    }
    return 0;
}

 

以上是关于18寒假第一测的主要内容,如果未能解决你的问题,请参考以下文章

18寒假第五测

18寒假第三测

18寒假第四测

18寒假第七测

18寒假第二测

寒假学习记录第二天