P8943 Deception Point

基环树算法题的分析与实现

不是,第一次被一道黄题卡了一个小时……
题目传送门

基环树

这是一棵树,它的本质就是一张没有环的图,有 n n n个点和 n − 1 n-1 n1条边。
在这里插入图片描述
这是一颗基环树,就是再一棵树上面加了一条边,所以它有 n n n个点 n n n条边。
在这里插入图片描述
题目中给出的 n n n n n n边就是一颗基环树。
题目先分为两类来讨论: A A A在环上与 A A A不在环上。

题目分析

A在环上

如果 A A A在环上,那么它就可以一直与 B B B绕着环跑(除了 A A A B B B一来就在同一个点的情况,但是题目中约束了 x i ≠ y i x_i\not=y_i xi=yi),就一定是 A A A获胜。

A不在环上

这时候由于两者都是绝顶聪明的,那么对于需要逃生的 A A A来说,最好的情况一定是跑到环上,因为这样就可以到了必胜的条件1。
但是,在 A A A移动的同时, B B B也会移动,比如存在以下情况。
(红色为 A A A,蓝色为 B B B
在这里插入图片描述

A A A跑到环上的时候, B B B也会到达 A A A所在的点(黄色的点), B B B必胜。

思路

通过上面的分析,可以得出两个步骤:
1.找出图中的环(有且只有一个),判断 A A A是否在环上。
2.若 A A A不在环上,比较 A A A到环上的距离与 B B B到距离 A A A最近的环上节点的距离(就是上图中蓝色点到黄色点的距离)。

实现

环的判断

对于图中的环,因为只有一个,所以可以用拓扑来求出所有环上的点。
怎么求呢?
对于一个无向图,当一个点的度数为 1 1 1时,那么就只有一条边连接它,其肯定不是环上的点,在一棵基环树中,这种点就是叶子节点。
所以,依次删去叶子结点,然后产生新的叶子结点,再删,最后删不掉的,就是连接了两个点的环。

queue<int>o;
for(int i=1;i<=n;i++)if(d[i]==1)o.push(i),vis[i]=1;
while(!o.empty()){
	int x=o.front();
	o.pop();
	for(int i=0;i<a[x].size();i++){
		int p=a[x][i];
		if(--d[p]==1)o.push(p),vis[p]=1;
	}
}
环外点到环的距离

我们可以考虑依次将换上的点入队,向环外找不是环上的点,依次记录步数。
相当于把环当成一个点来看。

while(!q.empty()){
	int x=q.front();
	q.pop();
	for(int i=0;i<a[x].size();i++){
		int y=a[x][i];
		if(vvs[y])continue;
		vvs[y]=1;
		dis[y]=dis[x]+1;//记录步数
		q.push(y);
	}
}
环上两点的距离

我们先随便在环上找一个点,将它标记为 1 1 1,然后用DFS遍历整个环,将剩下的每个点依次编号为 2 2 2 3 3 3 4 4 4……(不要用BFS,因为要么顺时针要么逆时针),对于环上两点 X X X Y Y Y的最小距离,使用两个点的编号来计算

mn=min(abs(dds[X]-dds[Y]),cnt-abs(dds[X]-dds[Y]));//dds[i]是点i的编号,cnt是环的长度
距离 x x x最近的环上节点

对于上图中的红色点,要怎么求黄色的点。
在寻找环外点到环的距离时,可以记录一下每个点对应的环上的点,修改后如下:

for(int i=1;i<=n;i++)f[i]=i;
while(!q.empty()){
		int x=q.front();
		q.pop();
		for(int i=0;i<a[x].size();i++){
			int y=a[x][i];
			if(vvs[y])continue;
			vvs[y]=1;
			dis[y]=dis[x]+1;
			f[y]=f[x];
			q.push(y);
		}
	}

然后……这道题就解决了。
代码:

#include<bits/stdc++.h>
#define endl putchar('\n')
using namespace std;
const int N=1e6+5;
int read(){
	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-'0',c=getchar();
	return x*f;
}
void print(int x){
	if(x<0)putchar('-'),x=-x;
	if(x<10){putchar(x+'0');return;}
	print(x/10);
	putchar(x%10+'0');
}
void putstr(string s){
	for(int i=0;i<s.size();i++)putchar(s[i]);
}
int n,m;
vector<int>a[N];
int vis[N];
int d[N];
int dis[N];
int vvs[N];
int dds[N];
int vvv[N];
int f[N];
int cnt;
void dfs(int x,int r){
	dds[x]=r;
	for(int i=0;i<a[x].size();i++){
		int y=a[x][i];
		if(vis[y])continue;
		if(vvv[y])continue;
		vvv[y]=1;
		dfs(y,r+1);
		vvv[y]=0;
		break;
	}
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		int u=read(),v=read();
		a[u].push_back(v);
		a[v].push_back(u);
		d[v]++,d[u]++;
	}
	queue<int>o;
	for(int i=1;i<=n;i++)if(d[i]==1)o.push(i),vis[i]=1;
	while(!o.empty()){
		int x=o.front();
		o.pop();
		for(int i=0;i<a[x].size();i++){
			int p=a[x][i];
			if(--d[p]==1)o.push(p),vis[p]=1;
		}
	}
	queue<int>q;
	for(int i=1;i<=n;i++){
		f[i]=i;
		dis[i]=1e9;
		if(vis[i])continue;
		dis[i]=0;
		vvs[i]=1;
		vvv[i]=0;
		q.push(i);
	}
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(int i=0;i<a[x].size();i++){
			int y=a[x][i];
			if(vvs[y])continue;
			vvs[y]=1;
			dis[y]=dis[x]+1;
			f[y]=f[x];
			q.push(y);
		}
	}
	for(int i=1;i<=n;i++){
		if(vis[i])continue;
		vvv[i]=1;
		dds[i]=1;
		dfs(i,1);
		break;
	}
	for(int i=1;i<=n;i++)cnt+=(!vis[i]);
	while(m--){
		int x=read(),y=read();
		if(!vis[x])putstr("Survive");
		else{
			int X=f[x],Y=f[y];
			int p=min(abs(dds[X]-dds[Y]),cnt-abs(dds[X]-dds[Y]));
			if(dis[x]<dis[y])putstr("Survive");
			else{
				if(dis[x]<dis[y]+p)putstr("Survive");
				else putstr("Deception");
			}
		}
		endl;
	}
}

后续:另一道关于基环树的题目

P8269 [USACO22OPEN] Visits S
这道题目为什么评绿啊?
其实很简单,经过模拟可以发现,不在环中的点,一定可以达到目标,而环中的点,总有一个点达不到目标,所以最后用所有的 v i v_i vi之和减去环中的最小 v i v_i vi就行了。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int read(){
	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-'0',c=getchar();
	return x*f;
}
void print(int x){
	if(x<0)putchar('-'),x=-x;
	if(x<10){putchar(x+'0');return;}
	print(x/10);
	putchar(x%10+'0');
}
int n;
int a[N],v[N];
int d[N];
int vis[N];
int ans;
int mn;
void dfs(int x){
	vis[x]=1;
	mn=min(mn,v[x]);
	if(vis[a[x]])return;
	dfs(a[x]);
	return;
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++)a[i]=read(),v[i]=read(),d[a[i]]++,ans+=v[i];
	queue<int>q;
	for(int i=1;i<=n;i++)if(d[i]==0)q.push(i);
	while(!q.empty()){
		int t=a[q.front()];
		vis[q.front()]=1;
		q.pop();
		if(--d[t]==0)q.push(t);
	}
	for(int i=1;i<=n;i++){
		if(vis[i])continue;
		mn=1e9;
		dfs(i);
		ans-=mn;
	}
	print(ans);
}
<think>好的,用户想要了解如何读入Deception-2016代码。首先,我需要确定用户的具体需求。Deception-2016可能是一个数据集或者某个特定的项目代码,但用户没有提供太多上下文。可能的情况包括:这是一个关于欺诈检测的数据集,或者是某个论文中的实验代码。 接下来,我应该考虑用户可能的背景。如果用户是研究人员或学生,他们可能需要指导如何正确加载和处理数据,或者如何运行相关的实验代码。由于用户提到“读入代码”,可能是指如何导入或执行该代码库中的某些功能,或者读取相关的数据集。 然后,我需要检查是否存在常见的Deception-2016资源。例如,在自然语言处理领域,可能有用于文本欺骗检测的数据集,比如Deceptive Opinion Spam Corpus 2016。如果是这样的话,读入数据可能涉及加载文本文件或CSV文件,使用Python的pandas库或者类似的工具。 另一个可能性是,Deception-2016是一个GitHub上的项目,用户需要克隆仓库并安装依赖项。这时候,步骤可能包括使用git clone,安装所需的包,并按照README中的说明操作。 由于信息不足,用户可能需要更明确的指导。因此,在回答中,我应该建议用户先明确Deception-2016的具体内容,并提供几种常见情况的处理方式。例如,如果是一个数据集,指导如何用Python读取;如果是代码库,说明如何安装和运行。同时,提醒用户检查文档和依赖项,确保环境配置正确。 此外,用户可能遇到路径错误、依赖包版本问题或者数据格式不匹配的情况,应建议他们查看错误信息,逐步调试,或者参考示例代码。如果用户的问题涉及特定领域,如机器学习模型,可能需要更详细的步骤,比如数据预处理、模型加载等。 最后,保持回答结构清晰,分步骤说明可能的解决方案,并鼓励用户提供更多细节以便进一步帮助。确保使用正确的中文表达,避免专业术语过于晦涩,同时保持技术准确性。</think>以下是对Deception-2016代码的解读建议步骤: 1. 明确代码来源 - 建议先确认代码是否来自论文《Deception Detection in Text and its Dependence on Training Data》相关项目 - 检查是否存在配套数据集(通常包含真实/虚假的酒店评论文本) 2. 环境准备 ```bash # 典型依赖项可能包含 Python 3.6+ pandas scikit-learn nltk tensorflow/pytorch(若含深度学习模型) ``` 3. 数据读取核心逻辑(假设为CSV格式) ```python import pandas as pd def load_deception_data(file_path): # 注意检查实际数据列的命名 df = pd.read_csv(file_path, names=['text', 'label'], header=0, encoding='latin-1') # 常见编码问题需注意 return df ``` 4. 特征工程关键点 $$ TF-IDF \space 公式:tfidf(t,d) = tf(t,d) \times \log\left(\frac{N}{df(t)}\right) $$ - 常见文本预处理流程:词干提取 → 停用词过滤 → n-gram生成 5. 模型架构注意事项 - 传统方法:SVM分类器常用参数 ```python from sklearn.svm import SVC clf = SVC(kernel='linear', C=1.0) ``` - 深度学习方法:LSTM网络的典型结构 $$ h_t = \tanh(W_{xh}x_t + W_{hh}h_{t-1} + b_h) $$ 6. 验证指标 - 需特别注意报告:准确率、召回率、F1值 $$ F1 = 2 \times \frac{precision \times recall}{precision + recall} $$ 建议执行顺序: 1. 克隆仓库 → 安装依赖 → 运行demo脚本 2. 从小规模数据子集开始测试 3. 逐步添加特征工程模块 4. 通过混淆矩阵分析模型表现 注意:由于没有具体代码链接,以上内容基于典型文本分类项目结构推测。建议提供具体代码片段可进行更精准分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值