Week7 作业C - TT 的美梦

题目大意

有N个点,每个点有一个权值。在这N个点间有M条有向边,每条边的长度等于 ( 终 点 权 值 − 起 点 权 值 ) 3 (终点权值 - 起点权值)^3 ()3。求1号点到其他点的距离。

输入

第一行输入 T,表明共有 T 组数据。(1 <= T <= 50)
对于每一组数据,第一行输入 N,表示点的个数。(1 <= N <= 200)
第二行输入 N 个整数,表示 1 ~ N 点的权值 a[i]。(0 <= a[i] <= 20)
第三行输入 M,表示有向边的条数。(0 <= M <= 100000)
接下来 M 行,每行有两个整数 A B,表示存在一条 A 到 B 的有向边。
接下来给出一个整数 Q,表示询问个数。(0 <= Q <= 100000)
每一次询问给出一个 P,表示求 1 号点到 P 号点的最小距离。

输出

每个询问输出一行,如果不可达或距离小于 3 则输出 ‘?’

基本思路

本题很显然是一个最短路问题,其难点在于存在负边,进而可能出现负环,我们要排除负环的干扰,并求得1号点到其他点的最短路长度。因为存在负边权,所以不能使用Dijkstra算法。

一种可行的方法是使用spfa算法。但是问题在于,负环会导致一些点被无限制的松弛下去,从而使得算法陷入死循环。为此,我们可以采用一个数组cnt,cnt[v]表示1号点到点v的最短路包含的点数(最短路长度+1),如果cnt[v]超过了总点数N,说明v在负环上或者可由负环上的点到达,这是给v打上标记(neg[v]=1),阻止v入队。

另外,一旦v在负环上或者可由负环上的点到达,那么可由v到达的点也会被无限制的松弛(如果不做处理),导致距离变为负无穷,因此这些点也需要被处理掉,可以通过从v点进行深度优先搜索dfs(v)来找到这些点,并打上标记neg,从而阻止这些点入队。

完整代码

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define inf 999999999
vector<pair<int, int> > G[205];
int T, N, M;
int dis[205], cnt[205], inq[205], a[205], neg[205];
void init()
{
	for(int i=0;i<=205;i++)
	{
		G[i].clear();
		cnt[i] = inq[i] = neg[i] = 0;
		dis[i] = inf;
	}
}
void read()
{
	cin>>N;
	for(int i=1;i<=N;i++)	cin>>a[i];
	cin>>M;
	int A, B;
	for(int i=1;i<=M;i++)
	{
		cin>>A>>B;
		G[A].push_back({B, (a[B]-a[A])*(a[B]-a[A])*(a[B]-a[A])});
	}
}
void dfs(int v)
{
	if(!neg[v])
	{
		neg[v]=1;
		for(int i=0, s=G[v].size();i<s;i++)	dfs(G[v][i].first);	
	}
}
void spfa()
{
	queue<int> Q;
	inq[1] = 1;
	dis[1] = 0;
	cnt[1] = 1;
	Q.push(1);
	while(!Q.empty())
	{
		int u = Q.front();	Q.pop();	inq[u] = 0;
		for(int i=0, s=G[u].size();i<s;i++)
		{
			int v = G[u][i].first;
			int w = G[u][i].second;
			if(!neg[v] && dis[v] > dis[u] + w)
			{
				dis[v] = dis[u] + w;
				cnt[v] = cnt[u] + 1;
				if(cnt[v] > N)	dfs(v);
				else if(!inq[v])
				{
					inq[v] = 1;
					Q.push(v);
				}
			}
		}
	}
}
void query(int Case)
{
	int Q;
	cin>>Q;
	int p;
	cout<<"Case "<<Case<<":"<<endl;
	for(int i=1;i<=Q;i++)
	{
		cin>>p;
		if(neg[p] || dis[p] < 3 || dis[p] == inf)	cout<<"?"<<endl;
		else	cout<<dis[p]<<endl;
	}
}
int main ()
{
	cin>>T;
	for(int i=1;i<=T;i++)
	{
		init();
		read();
		spfa();
		query(i);
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在第4周的可重复研究项目中,我将继续探索如何使用开放源代码工具和技术来实现可重复性和透明度。 首先,我将继续使用版本控制系统(如Git),以便跟踪我研究项目中的所有更改和改进。这将确保我能够回溯到每个版本的数据和代码,并对项目进行可重复性验证。在本周内,我还将学习更多关于Git分支和合并的知识,以便更好地组织和管理我的项目。 另外,我还将使用Jupyter Notebook来记录我的实验过程和结果。Jupyter Notebook提供了一个互动环境,可以将代码、文档和图形化结果结合在一起,使得我的研究成果更加易于理解和重现。我会确保我的Notebook中包含了所有必要的步骤和解释,以便他人能够准确地复现我的研究。 为了进一步提高可重复性,我还将采取一些数据预处理和清洗的措施。这些措施包括去除异常值、处理缺失数据和标准化数据等。我将确保我的数据处理过程明确记录,并提供相应的代码和文档,以便他人能够按照相同的步骤进行处理。 最后,我还计划使用容器化技术(如Docker)来实现我的研究项目的可移植性。通过将我的环境和依赖项封装在一个容器中,我可以确保其他人能够在不同的计算机和操作系统上轻松地运行我的代码和分析。 综上所述,第4周的可重复研究项目将继续探索一系列工具和技术,旨在提高我的研究项目的可重复性和透明度。通过使用版本控制系统、Jupyter Notebook、数据处理和清洗措施以及容器化技术,我将确保我的研究成果可以被其他人准确地重现和验证。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值