复制代码

历年NOIP真题

P2296 NOIP2014提高组寻找道路

题目描述
在有向图 \(G\) 中,每条边的长度均为 \(1\),现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

  1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
  2. 在满足条件\(1\)的情况下使路径最短。
    注意:图 \(G\) 中可能存在重边和自环,题目保证终点没有出边。
    请你输出符合条件的路径的长度
    输入格式
    第一行有两个用一个空格隔开的整数 \(n\)\(m\),表示图有 \(n\) 个点和 \(m\) 条边。
    接下来的 \(m\) 行每行 \(2\) 个整数 \(x,y\),之间用一个空格隔开,表示有一条边从点 \(x\) 指向点\(y\)
    最后一行有两个用一个空格隔开的整数 \(s, t\),表示起点为 \(s\),终点为 \(t\)
    输出格式
    输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出\(-1\)
    输入1
3 2
1 2
2 1
1 3

输出1

-1

输入2

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

输出2

3

分析
题目要求所有点的出边所指向的点都直接与间接与终点联通。
首先我的思路是用一个并查集将与终点有连接的点记录起来,但是有重边和自环,没办法用并查集。
我们采取SPFA建反图跑一边最短路,以终点为起点,将每个点到终点的最短路记录下来,如果不能到达,那么在BFS中就不加入。
代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 6e6;
int n,m,u,v,s,t;
struct  edge{
    int from;
    int to;
    int dis;
    int next;
}e[N],E[N];
int head[N],cnt;
void add(int u,int v)
{
    ++cnt;
    e[cnt].from = u;
    e[cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}
int HEAD[N],tot;
void add2(int u,int v,int w)
{
     ++tot;
     E[tot].from = u;
     E[tot].to = v;
     E[tot].dis = w;
     E[tot].next = HEAD[u];
     HEAD[u] = tot;
}
int mapp[N];
bool vis[N];
queue<int> q;
void SPFA(int u)
{
    memset(mapp,0x3f,sizeof(mapp));
    memset(vis,0,sizeof(vis));
    mapp[u] = 0; vis[u] = true;
    q.push(u);
    while(!q.empty())
    {
       int x = q.front();
       vis[x] = false;
       q.pop();
       for(int i=HEAD[x];i;i=E[i].next)
       {
           int y = E[i].to;
           if(mapp[y] > mapp[x] + E[i].dis)
           {
               mapp[y] = mapp[x] + E[i].dis;
               if(vis[y] == false)
               {
                  vis[y] = true;
                  q.push(y);
               }
           }
       }
    }
}
int dis[N];
bool check(int x)
{
    for(int i=head[x];i;i=e[i].next)
    {
        int y = e[i].to;
        if(mapp[y] == 1061109567) return false;
    }
    return true;
}
void bfs()
{   
    memset(vis,0,sizeof(vis));
    queue<int> q;
    q.push(s);
    memset(dis,0x3f,sizeof(dis));
    dis[s] = 0;
    vis[s] = true;
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        for(int i=head[x];i;i=e[i].next)
        {
            int y = e[i].to;
            if(vis[y] == true)  continue;
            if(mapp[y] == 1061109567 || check(y) == false) continue;
            //如果它所连的边也不能到达终点,那么也将它排除。
            int w = 1;
            if(dis[y] > dis[x] + w) 
            dis[y] = dis[x] + w;
            if(vis[y] == false)
            q.push(y);
            vis[y] = true;
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v;
        add(u,v);
        add2(v,u,1);
    }
    cin>>s>>t;
    SPFA(t);
    bfs();
    if(dis[t] == 1061109567) puts("-1");
    else cout<<dis[t];
    return 0;
}

P7113 NOIP2020排水系统

题目描述
对于一个城市来说,排水系统是极其重要的一个部分。
有一天,小 C 拿到了某座城市排水系统的设计图。排水系统由 n 个排水结点(它们从1∼n 编号)和若干个单向排水管道构成。每一个排水结点有若干个管道用于汇集其他排水结点的污水(简称为该结点的汇集管道),也有若干个管道向其他的排水结点排出污水(简称为该结点的排出管道)。
排水系统的结点中有 m个污水接收口,它们的编号分别为 1,2,3, m污水只能从这些接收口流入排水系统,并且这些结点没有汇集管道。排水系统中还有若干个最终排水口,它们将污水运送到污水处理厂,没有排出管道的结点便可视为一个最终排水口。
现在各个污水接收口分别都接收了1 吨污水,污水进入每个结点后,会均等地从当前结点的每一个排出管道流向其他排水结点,而最终排水口将把污水排出系统。
现在小 C 想知道,在该城市的排水系统中,每个最终排水口会排出多少污水。该城市的排水系统设计科学,管道不会形成回路,即不会发生污水形成环流的情况。
输入格式
第一个两个用单个空格分隔的整数 n,m。分别表示排水结点数与接收口数量。
接下来 n行,第 i 行用于描述结点 i 的所有排出管道。其中每行第一个整数
表示其排出管道的数量,接下来个用单个空格分隔的整数依次表示管道的目标排水结点。
保证不会出现两条起始结点与目标结点均相同的管道。
输出格式
输出若干行,按照编号从小到大的顺序,给出每个最终排水口排出的污水体积。其中体积使用分数形式进行输出,即每行输出两个用单个空格分隔的整数 p,q,表示排出的污水体积为p / q。要求 p 与 q 互素,q = 1 时也需要输出 q。
输入 #1

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

输出 #1

1 3
2 3

输入 #2

10 1
5 2 3 4 5 6
2 7 8
2 8 10
2 9 7
1 9
3 7 8 9
1 10
0
1 10
0

输出 #2

4 15
11 15

分析
保证不会出现两条起始结点与目标结点均相同的管道。这表明了这是一个裸的拓扑排序,需要注意的是用分数表示,分数要约分到最简,还有这毒瘤的数据。
unsigned long long 也过不了,会WA一个点,需要用__int128.
注意printf和cout 都无法输出__int 128的数据,需要用字符形式输出。
代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cstring>
#define  lll  __int128
using namespace std;
const int N=2e7;
lll gcd(lll a,lll b)
{
    if(b == 0)  return a;
    return gcd(b,a%b);
}
struct  edge{
    int from;
    int to;
    int dis;
    int next;
}e[N];
int head[N],cnt;
void add(int u,int v)
{
    ++cnt;
    e[cnt].from = u;
    e[cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}
struct node{
    lll son;
    lll mom;
    node()
    {
        lll son = 0;
        lll mom = 0;
    }
}ans[N];
node check(node a,node b)
{
    node sum;
    if(a.son == 0 && a.mom == 0)
    {
        sum.son = b.son;
        sum.mom = b.mom;
        return sum;
    }
    lll p = a.mom/gcd(a.mom,b.mom)*b.mom;
    sum.mom = p;
    sum.son = (p/a.mom*a.son)+(p/b.mom*b.son);
    lll t = gcd(sum.son,sum.mom);
    sum.son /= t;
    sum.mom /= t;
    return sum;
}
int n,m;
int x;
int num[N];
int ru[N],chu[N];
queue<int> q;
void print(lll n) {
    if(n > 9) print(n / 10);
    putchar(n % 10 + 48);
    //n % 10+'0'(48)表示字符0~9   
    //putchar输出的是字符。
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>num[i];
        for(int j=1;j<=num[i];j++)
        {
            cin>>x;
            add(i,x);
            ru[x]++;
            chu[i]++; 
        }
    }
    for(int i=1;i<=n;i++)
    if(ru[i] == 0)
    {
        q.push(i);
        ans[i].son = 1;
        ans[i].mom = 1;
    }
    while(!q.empty())
    {
        int x = q.front();
        if(num[x] != 0) ans[x].mom *= num[x];
        q.pop();
        for(int i=head[x];i;i=e[i].next)
        {
            int y = e[i].to;
            ans[y] = check(ans[y],ans[x]);
            ru[y]--;
            if(ru[y] == 0) q.push(y);
            //cout<<y<<" "<<ans[y].son<<" "<<ans[y].mom<<endl;
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(chu[i] == 0)
        {
            lll w = gcd(ans[i].son,ans[i].mom);
            ans[i].mom /= w;//再约分一次保证互质
            ans[i].son /= w;
            print(ans[i].son);
            printf(" ");
            print(ans[i].mom);
            printf("\n");
        }
        
    }
    return 0;
}
posted @ 2021-10-02 19:40  Elgina  阅读(489)  评论(0)    收藏  举报