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;
}

原文地址:https://www.cnblogs.com/EdSheeran/p/8409990.html

时间: 2024-10-06 06:38:33

18寒假第一测的相关文章

18寒假第二测

第一题:二维树状数组,bit[x][y]表示从(1,1)到(x,y)的和,二维的坐标从一维的推过来,正确性可以用一个递增和一个递减的序列单调性证明,至于构图就当黑箱吧 #include <cstdio> int n, m, q; struct Case1 { int bit[100010]; void modify( int p, int d ) { for( int i = p; i <= m; i += i & -i ) bit[i] += d; } int query( i

18寒假13测

题目名称 buy slide divide 输入 buy.in slide.in divide.in 输出 buy.out slide.out divide.out 每个测试点时限 1秒 1秒 1秒 内存限制 256MB 256MB 256MB 测试点数目 10 10 10 每个测试点分值 10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 buy description: 地主zxr想买一些长方形的土地,所有的土地可以分为若干组,每一组的土地的价格为这一组里的最长的长乘上最

18寒假12测

Day1 题目名称 party array treasure 输入 party.in array.in treasure.in 输出 party.out array.out treasure.out 每个测试点时限 1秒 1秒 1秒 内存限制 64MB 64MB 64MB 测试点数目 10 10 10 每个测试点分值 10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 party 题目描述: 在M公司里,每个人只有一个直属上司(除了boss).这个公司举办派对,每个人可以给派

18寒假第三测

第一题:找LCA,两点之间的距离=他们各自到起点的距离 - 2*LCA到起点的距离 #include<bits/stdc++.h> using namespace std; const int maxn = 100015, P = 20; int head[2 * maxn],to[2 * maxn],last[2 *maxn],co[2 * maxn],dep[maxn], idx, anc[maxn][P+1],dis[maxn]; void dfs(int u,int from){ //

18寒假第六测

第一题:乘法修改的线段树 一定不能将change,modify分类讨论定两个标记,会有顺序影响 lazy标记一定要long long,又忘了... 代码和上一次差不多 第二题:离散暴力,也可以扫描线 离散时要将格子映射成点,不然会出现以下情况: 算横着的小矩形宽就是2,算黄色面积宽还是2,因为没有2让3去减 如果映射成点,就像这样,,放图比较好理解,就像扫描线,一个叶子节点存的是一个左闭右开的区间 也可以离散+扫描线,但还没写出来 #include <bits/stdc++.h> using

18寒假第五测

第一题 线段树 树状数组存差b[i] = a[i]-a[i-1],反正是单点查询,我为什么没想到...很傻的用线段树 #include<bits/stdc++.h> using namespace std; #define maxn 100005 #define ll long long int n, m, a[maxn]; struct SegmentTree{ struct node{ ll sum; int lazy; }; node Tree[maxn << 2]; #de

20145327寒假第一周学习总结

学习科目:离散数学第一部分-数理逻辑 通过对PPT的学习掌握了命题逻辑基本概念 命题逻辑等值演算 命题逻辑推理理论 一阶逻辑基本概念 一阶逻辑等值演算与推理理论. 笔记: 两个重要量词分配等值式: 所有有关数理逻辑的题都是在这些公式的基础上进行推理,掌握好这些公式命题逻辑部分的题基本不会有大问题,多做题熟悉公式(期末考试中是第三部分图论出了问题,所以这一部分复习起来还是相对容易,着重放在二三部分).

BZOJ NOI十连测 第一测 T2

思路:看到这题,就感觉是一道很熟悉的题目: http://www.cnblogs.com/qzqzgfy/p/5535821.html 只不过这题的K最多可以到N,而且边权不再只是1,考试的时候yy了一下做法: 找k次直径,第一次把边取反,要是第二次再取到同样的边,那就把它变成0,毕竟每条边只经过2次嘛,YY的很好,实际上,交上去,5分TAT 后来听以为神犇说不是取0,而是继续取反,每条边取一次就取反一次,woc.. 1 #include<cstdio> 2 #include<cmath

BZOJ NOI十连测 第一测 T1

思路:首先考虑t=1的情况,t等于1,那么所有位置的颜色相同,我们不用考虑概率的问题,那么,k+d*x在模d下都相等,我们考虑预处理一个数组s[i][j],代表d为i,起始位置为j的等差数列的和,这个可以证明,当模小于等于sqrt(n)的时候可以完美解决,时间复杂度为N^1.5,对于d大于sqrt(n)的情况,只需要暴力枚举就可以了. 再考虑t>=2的情况,我们选的颜色一定是颜色数最少的那个,颜色数最少的颜色的期望绝对是最小的,然后,我们分k的左边和k的右边进行计算,我们这里称呼k+d*x的位置