C++ 快读两种方法

本文介绍了两种C++输入输出的优化方法:T宝法和究极优化法,详细展示了它们的实现代码。通过实践对比,T宝法在Codeforces平台上的运行时间为872ms,而究极优化法只需421ms。对于时间敏感的竞赛编程或高效率需求,使用究极优化法更为合适。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

法一 T宝法:

ios::sync_with_stdio(false);
cin.tie(0);

法二:究极优化法:

namespace Fastio
{
    struct Reader
    {
        template <typename T> Reader& operator >> (T &x)
        {
            x = 0;
            short f = 1;
            char c = getchar();
            while (c < '0' || c > '9') { if (c == '-') f *= -1; c = getchar(); }
            while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
            x *= f;
            return *this;
        }
        Reader& operator >> (double &x)
        {
            x = 0;
            double t = 0;
            short f = 1, s = 0;
            char c = getchar();
            while ((c < '0' || c > '9') && c != '.') { if (c == '-') f *= -1; c = getchar(); }
            while (c >= '0' && c <= '9' && c != '.') x = x * 10 + (c ^ 48), c = getchar();
            if (c == '.') c = getchar();
            else { x *= f; return *this; }
            while (c >= '0' && c <= '9') t = t * 10 + (c ^ 48), s++, c = getchar();
            while (s--) t /= 10.0;
            x = (x + t) * f;
            return *this;
        }
        Reader& operator >> (long double &x)
        {
            x = 0;
            long double t = 0;
            short f = 1, s = 0;
            char c = getchar();
            while ((c < '0' || c > '9') && c != '.') { if (c == '-') f *= -1; c = getchar(); }
            while (c >= '0' && c <= '9' && c != '.') x = x * 10 + (c ^ 48), c = getchar();
            if (c == '.') c = getchar();
            else { x *= f; return *this; }
            while (c >= '0' && c <= '9') t = t * 10 + (c ^ 48), s++, c = getchar();
            while (s--) t /= 10.0;
            x = (x + t) * f;
            return *this;
        }
        Reader& operator >> (__float128 &x)
        {
            x = 0;
            __float128 t = 0;
            short f = 1, s = 0;
            char c = getchar();
            while ((c < '0' || c > '9') && c != '.') { if (c == '-') f *= -1; c = getchar(); }
            while (c >= '0' && c <= '9' && c != '.') x = x * 10 + (c ^ 48), c = getchar();
            if (c == '.') c = getchar();
            else { x *= f; return *this; }
            while (c >= '0' && c <= '9') t = t * 10 + (c ^ 48), s++, c = getchar();
            while (s--) t /= 10.0;
            x = (x + t) * f;
            return *this;
        }
        Reader& operator >> (char &c)
        {
            c = getchar();
            while (c == ' ' || c == '\n' || c == '\r') c = getchar();
            return *this;
        }
        Reader& operator >> (char *str)
        {
            int len = 0;
            char c = getchar();
            while (c == ' ' || c == '\n' || c == '\r') c = getchar();
            while (c != ' ' && c != '\n' && c != '\r') str[len++] = c, c = getchar();
            str[len] = '\0';
            return *this;
        }
        Reader& operator >> (string &str)
        {
            str.clear();
            char c = getchar();
            while (c == ' ' || c == '\n' || c == '\r') c = getchar();
            while (c != ' ' && c != '\n' && c != '\r') str.push_back(c), c = getchar();
            return *this;
        }
        Reader() {}
    } cin;
    const char endl = '\n';
    struct Writer
    {
        const int Setprecision = 6;
        typedef int mxdouble;
        template <typename T> Writer& operator << (T x)
        {
            if (x == 0) { putchar('0'); return *this; }
            if (x < 0) putchar('-'), x = -x;
            static short sta[40];
            short top = 0;
            while (x > 0) sta[++top] = x % 10, x /= 10;
            while (top > 0) putchar(sta[top] + '0'), top--;
            return *this;
        }
        Writer& operator << (double x)
        {
            if (x < 0) putchar('-'), x = -x;
            mxdouble _ = x;
            x -= (double)_;
            static short sta[40];
            short top = 0;
            while (_ > 0) sta[++top] = _ % 10, _ /= 10;
            if (top == 0) putchar('0');
            while (top > 0) putchar(sta[top] + '0'), top--;
            putchar('.');
            for (int i = 0; i < Setprecision; i++) x *= 10;
            _ = x;
            while (_ > 0) sta[++top] = _ % 10, _ /= 10;
            for (int i = 0; i < Setprecision - top; i++) putchar('0');
            while (top > 0) putchar(sta[top] + '0'), top--;
            return *this;
        }
        Writer& operator << (long double x)
        {
            if (x < 0) putchar('-'), x = -x;
            mxdouble _ = x;
            x -= (long double)_;
            static short sta[40];
            short top = 0;
            while (_ > 0) sta[++top] = _ % 10, _ /= 10;
            if (top == 0) putchar('0');
            while (top > 0) putchar(sta[top] + '0'), top--;
            putchar('.');
            for (int i = 0; i < Setprecision; i++) x *= 10;
            _ = x;
            while (_ > 0) sta[++top] = _ % 10, _ /= 10;
            for (int i = 0; i < Setprecision - top; i++) putchar('0');
            while (top > 0) putchar(sta[top] + '0'), top--;
            return *this;
        }
        Writer& operator << (__float128 x)
        {
            if (x < 0) putchar('-'), x = -x;
            mxdouble _ = x;
            x -= (__float128)_;
            static short sta[40];
            short top = 0;
            while (_ > 0) sta[++top] = _ % 10, _ /= 10;
            if (top == 0) putchar('0');
            while (top > 0) putchar(sta[top] + '0'), top--;
            putchar('.');
            for (int i = 0; i < Setprecision; i++) x *= 10;
            _ = x;
            while (_ > 0) sta[++top] = _ % 10, _ /= 10;
            for (int i = 0; i < Setprecision - top; i++) putchar('0');
            while (top > 0) putchar(sta[top] + '0'), top--;
            return *this;
        }
        Writer& operator << (char c) { putchar(c); return *this; }
        Writer& operator << (char *str)
        {
            int cur = 0;
            while (str[cur]) putchar(str[cur++]);
            return *this;
        }
        Writer& operator << (const char *str)
        {
            int cur = 0;
            while (str[cur]) putchar(str[cur++]);
            return *this;
        }
        Writer& operator << (string str)
        {
            int st = 0, ed = str.size();
            while (st < ed) putchar(str[st++]);
            return *this;
        }
        Writer() {}
    } cout;
}
using namespace Fastio;
#define cin Fastio::cin
#define cout Fastio::cout
#define endl Fastio::endl
支持__int128和__float128以及string

E - Cross Swapping

同一题目,时限 1 s,T宝法 872ms,究极优化 421ms。

总结:除了cf之外 T宝法足以,如果自己算法时间复杂度算的没错还是卡了,用究极优化。

#include<bits/stdc++.h> using namespace std; #define re register #define il inline il int read() { re int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x*f; }//,不理解的同学用cin代替即可 #define inf 123456789 #define maxn 5005 #define maxm 200005 struct edge { int v,w,next; }e[maxm<<1]; //注意是无向图,开两倍数组 int head[maxn],dis[maxn],cnt,n,m,tot,now=1,ans; //已经加入最小生成树的的点到没有加入的点的最短距离,比如说1和2号节点已经加入了最小生成树,那么dis[3]就等于min(1->3,2->3) bool vis[maxn]; //链式前向星加边 il void add(int u,int v,int w) { e[++cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt; } //入数据 il void init() { n=read(),m=read(); for(re int i=1,u,v,w;i<=m;++i) { u=read(),v=read(),w=read(); add(u,v,w),add(v,u,w); } } il int prim() { //先把dis数组附为极大值 for(re int i=2;i<=n;++i) { dis[i]=inf; } //这里要注意重边,所以要用到min for(re int i=head[1];i;i=e[i].next) { dis[e[i].v]=min(dis[e[i].v],e[i].w); } while(++tot<n)//最小生成树边数等于点数-1 { re int minn=inf;//把minn置为极大值 vis[now]=1;//标记点已经走过 //枚举每一个没有使用的点 //找出最小值作为新边 //注意这里不是枚举now点的所有连边,而是1~n for(re int i=1;i<=n;++i) { if(!vis[i]&&minn>dis[i]) { minn=dis[i]; now=i; } } ans+=minn; //枚举now的所有连边,更新dis数组 for(re int i=head[now];i;i=e[i].next) { re int v=e[i].v; if(dis[v]>e[i].w&&!vis[v]) { dis[v]=e[i].w; } } } return ans; } int main() { init(); printf("%d",prim()); return 0; } 这是一道最小生成树模板的代码,请告诉我代码中的dis数组是什么
03-08
<think>好的,我现在需要理解用户提供的这段代码中的dis数组的作用。这段代码是用C++实现的Prim算法求解最小生成树的问题。用户的问题是关于代码中dis数组的具体含义和功能。 首先,我应该回忆一下Prim算法的基本思想。Prim算法是一种贪心算法,用于在加权连通图中找到最小生成树。它的基本步骤是从一个起始节点开始,逐步扩展生成树,每次选择连接树和非树节点的边中权值最小的那条边,并将对应的节点加入到生成树中。 接下来,我需要仔细阅代码,特别是涉及dis数组的部分。代码的结构大致如下: 1. 使用链式前向星存储图的边。 2. init函数取输入并构建图的邻接表。 3. prim函数实现Prim算法,其中使用dis数组。 在prim函数中,首先初始化dis数组,将除了起始点(假设是节点1)之外的所有节点的dis值设为无穷大。然后,遍历起始点的所有邻接边,更新这些邻接节点的dis值为对应边的权值,如果权值更小的话。例如,如果起始点是1,那么对于每个与1相连的节点v,dis[v]会被初始化为边1-v的权值中的最小值,以处理可能的重复边。 接下来进入循环,直到所有节点都被访问(即生成树包含n个节点)。在每次循环中,找到当前dis数组中未访问节点中的最小值,即找到下一个要加入生成树的节点now。然后,将对应的minn(即当前的dis[now])累加到ans中,表示这条边的权值被计入总权重。随后,遍历now节点的所有邻接边,更新这些邻接节点的dis值,如果通过now到达这些节点的边的权值比当前dis中的值更小的话。 这里的dis数组的作用需要明确。根据Prim算法的描述,dis数组应该维护的是当前生成树集合到各个未加入生成树的节点的最小权值边。也就是说,对于每个未加入的节点v,dis[v]保存的是连接生成树内节点到v的所有边中的最小权值。每次选择dis中最小的那个值对应的节点加入生成树,并更新其他节点的dis值。 具体来说,代码中的dis数组在初始化时,处理了起始点1的所有邻接边,此时生成树只有节点1,所以dis[v]是1到v的直接边的权值。之后,当新的节点now被加入生成树后,遍历now的所有邻接边,检查是否这些边能够提供更小的权值来更新其他未加入节点的dis值。例如,如果之前某个节点u的dis值是5(通过之前的生成树节点到达),而now到u的边权是3,那么dis[u]会被更新为3,因为现在通过now到达u更优。 这样,dis数组始终保持的是当前生成树到各个未加入节点的最小权值。每次循环选择最小的dis值,并将其对应的节点加入生成树,保证了每一步都是当前最优的选择,从而整体构成最小生成树。 此外,代码中的vis数组用于标记哪些节点已经被加入到生成树中,避免重复处理。ans变量累加每次选择的边的权值,最终得到最小生成树的总权值。 总结一下,dis数组在Prim算法中的角色是记录当前生成树集合到每个未加入节点的最小边的权值。通过不断选择这些最小权值的边,逐步构建最小生成树。因此,在代码中,dis数组的具体含义就是每个节点到当前生成树的最小距离(即权值),每次迭代选择最小的那个,并更新相关节点的距离。</think>这段代码实现的是Prim算法求解最小生成树。其中`dis`数组的作用是记录**当前生成树到各个节点的最短距离**,具体来说: $$dis[i] = \text{节点i与当前生成树中任意节点相连的最小边权值}$$ ### 关键点解析: 1. **初始化过程** - 起始时将`dis[1]`设为0(默认起点为1号节点) - 其他节点初始化为无穷大(`inf`) - 通过遍历起点1的邻接边,将直接相连节点的`dis`值更新为对应边权 2. **动态更新机制** ```cpp for(re int i=head[now];i;i=e[i].next) { re int v=e[i].v; if(dis[v]>e[i].w && !vis[v]) { dis[v] = e[i.w; // 松弛操作 } } ``` 每当新节点`now`加入生成树后,会遍历其所有邻接边: - 若发现更小的边权(`e[i].w < dis[v]`) - 则更新`dis[v]`为这个更小的值 3. **贪心选择策略** 每次循环选择当前`dis`数组中: - 未被访问(`!vis[i]`) - 具有最小边权的节点(`minn`) 将其加入生成树,并将该边权计入总权重`ans` ### 示例说明: 假设当前生成树包含节点{1,2}: - 节点3的`dis[3]`值为min(1→3的边权, 2→3的边权) - 这样能保证每次扩展生成树时,总是选择代价最小的边 这个数组是Prim算法的核心,通过$$O(n^2)$$的时间复杂度(可用堆优化至$$O(m \log n)$$)逐步构建最小生成树。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值