天梯赛自主练习5补题 (17年大区赛)

题目

l2-4功夫传人
题意: 给定以1为根的有向树,根节点的点权为Z,每传给子节点,就减少r%,该子节点是叶子节点,叶子节点会翻a[i]倍。
思路: 感觉这个题意有点迷,题干说没传一代就减弱r%,除非遇到叶子,就说明叶子不该减弱r%。但是这样连样例都过不了,好怪。
建完图dfs求和即可。
!又忘了特判,如果n==1我又没特判,wa了一分。
时间复杂度: O(n)
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 2e5+10;
int n,m,k,T;
// #define int long long
// #define double long double
double st;
double r;
double a[N];
double ans[N];
vector<int> va[N];
void dfs(int cur)
{
	for(int i=0;i<va[cur].size();++i)
	{
		int j = va[cur][i];
		if(a[j] != -1)
		{
			ans[j] = ans[cur] *(1.0-r) * a[j];
		}
		else
		{
			ans[j] = ans[cur] * (1.0-r);
			dfs(j);
		}
	}
}
void solve()
{
	cin>>n>>st>>r;
	r *= 0.01;
	for(int i=0;i<n;++i) a[i] = -1;
	for(int i=0;i<n;++i)
	{
		int num; cin>>num;
		int x;
		if(num == 0)
		{
			cin>>a[i];
		}
		else
		{
			while(num--)
			{
				int x; cin>>x;
				va[i].push_back(x);
			}
		}
	}
	if(n == 1 && a[0] != 0)
	{
		cout<<(int)(st*a[0]);
		return ;
	}
	// cout<<(17.82*7)<<"\n";
	double sum = 0;
	ans[0] = st;
	dfs(0);
	for(int i=0;i<n;++i) 
	{
		// cout<<i<<":"<<ans[i]<<"\n";
		if(a[i] != -1)
		{
			sum += ans[i];
		}
	}
	
// 	cout<<(int)sum;
	printf("%lld",(ll)sum);
}
signed main(void)
{
	solve();
	return 0;
}

l3-2周游世界
题意: 给定m条双向公交路线,给定k组查询,查询从st到ed的最短路径。如果路径不唯一,则输出换乘次数最少的路径。题目保证该路径唯一。注意:输出路径并不是输出从起点到终点的路径,而是输出每次换乘的起点和终点,以及最后一次不换乘到达终点的起点和终点。
思路: 当时心态有点小炸,感觉这题也太麻烦了,乱七八糟的。最短路可能不太好做这个题,而且数据量只有100,直接dfs即可。
1.建图,同一路线的相邻两点之间连边。而不是一个点连所有其他点。
2.用数组line[x][y]或者map记录一下从x走到y属于哪个线路。
3.dfs的时候记录路径,如果到达终点,遍历一遍路径求得换乘次数。
!dfs之前没有把起点加入路径,但是能过样例,一直wa。
时间复杂度: O(能过)
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 9999+20;
#define mem(a,x) memset(a,x,sizeof(a))
int line[N][N];
bool vis[N];
int st,ed;
vector<int> va[N];
vector<int> v; //路径
vector<int> a; //答案
int ans = 1e9;
int res = 1e9;
int n,m,k,T;
int fun()
{
	int cnt = 0;
	int lst = 0;
	for(int i=1;i<v.size();++i)
	{
		int l = v[i-1];
		int r = v[i];
		if(lst == 0)
		{
			lst = line[l][r];
		}
		else
		{
			if(lst != line[l][r])
			{
				cnt++;
				lst = line[l][r];
			}
		}
	}
	return cnt-1;
}
void dfs(int cur,int num)
{
	if(num > ans) return ;
	if(cur == ed)
	{
		int c = fun();
		if(num < ans)
		{
			ans = num;
			res = c;
			a = v;
		}
		else if(num == ans)
		{
			if(c < res)
			{
				res = c;
				a = v;
			}
		}
		return ;
	}
	for(int i=0;i<va[cur].size();++i)
	{
		int j = va[cur][i];
		if(!vis[j])
		{
			vis[j] = 1;
			v.push_back(j);
			dfs(j,num+1);
			v.pop_back();
			vis[j] = 0;
		}
	}
}
void solve()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		int num; cin>>num;
		vector<int> vv;
		while(num--)
		{
			int x; cin>>x;
			vv.push_back(x);
		}
		for(int j=1;j<vv.size();++j)
		{
			int l = vv[j-1];
			int r = vv[j];
			va[l].push_back(r);
			va[r].push_back(l);
			line[l][r] = line[r][l] = i;
		}
	}
	cin>>k;
	while(k--)
	{
		cin>>st>>ed;
		ans = res = 1e9;
		mem(vis,false); vis[st] = 1;
		v.clear();
		a.clear();
        v.push_back(st);
		dfs(st,0);
		// cout<<ans<<"?\n";
		if(ans == 1e9)
		{
			printf("Sorry, no line is available.\n");
		}
		else 
		{
			printf("%d\n",ans);
			int lst = 0;
			int start = st;
			for(int i=1;i<a.size();++i)
			{
				int l = a[i-1];
				int r = a[i];
				if(lst == 0)
				{
					lst = line[l][r];
				}
				else
				{
					if(lst != line[l][r])
					{
						printf("Go by the line of company #%d from %04d to %04d.\n",lst,start,l);
						lst = line[l][r];
						start = l;
					}
				}
			}
			printf("Go by the line of company #%d from %04d to %04d.\n",lst,start,ed);
		}
	}
}
signed main(void)
{
	solve();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值