燕山大学数据结构课设--练习(1)

第一题

#include<iostream>
using namespace std;
int n;
char c;
int main()
{
	cin>>n>>c;
	for(int i=1;i<=(n+1)/2;i++)//四舍五入
	{
		for(int j=1;j<=n;j++)
			cout<<c;
		cout<<"\n";
	}	
} 

第二题    暴力枚举

L<1000  暴力枚举区间  0<K<10  数据范围开LL

#include<iostream>
using namespace std;
int len,k;
string s;
typedef long long ll;
bool check(int a,int b)
{
	ll t=0;
	for(int i=a;i<=b;i++)
		t*=10,t+=(s[i]-'0');
	if(t==0||t==1) return false;
	for(int i=2;i*i<=t;i++)
		if(t%i==0) 
			return false;
	for(int i=a;i<=b;i++)
		cout<<s[i];
	return true;
}
int main()
{
	cin>>len>>k>>s;
	for(int i=0;i+k-1<len;i++)
	{
		int j=i+k-1;
		if(check(i,j)) return 0;
	}
	cout<<404;
} 

第三题    模拟

#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1e4+5;
struct person
{
	int mon;//所有的钱数 
	int pos;//编号 
	int cnt;//抢到的个数 
}per[N];
bool cmp(person a,person b)//收入降序,个数降序,编号增序 
{
	if(a.mon!=b.mon) return a.mon>b.mon;
	if(a.cnt!=b.cnt) return a.cnt>b.cnt;
	return a.pos<b.pos;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) per[i].pos=i;
	for(int i=1;i<=n;i++)
	{
		int k;cin>>k;
		for(int j=1;j<=k;j++)
		{
			int a,b;
			cin>>a>>b;
			per[i].mon-=b;//减去发红包的人 
			per[a].mon+=b;//加上收红包的人 
			per[a].cnt++;
		}
	}
	sort(per+1,per+n+1,cmp);
	for(int i=1;i<=n;i++)//输入数据以分为单位,输出结果以元为单位
		cout<<per[i].pos<<" "<<fixed<<setprecision(2)<<per[i].mon*1.0/100<<endl;
}

第四题  单源最短路+堆优化 

题意:森森从1号点走到n号点,点之间的边权有两种:现金和旅游金 ,每个点的都有一个现金兑换旅游金的汇率,且如果在某点换币,则必须将现金全部换为旅游金

        问题可以转化为找一个中间点x在1~x使用的现金,和在x点的汇率下,在x~n使用的旅游金对应的现金,两者之和的最小值

        而在1~x使用的现金的最小值即为点1到点x以现金为边权的最短距离,在x~n使用的旅游金的最小值即为点n到点x以旅游金为边权的最短距离

        看下数据范围 1≤n≤1e5,1≤m≤2e5  可以考虑 堆实现的dijkstra 复杂度为o(mlogn)

        以现金为边权,正向建图,以1为起点做dijkstra;以旅游金为边权,反向建图,以n为起点做dijkstra,分别求中间点到两点的最短距离

接下来就有了第一版代码:

 正反做完dijkstra后,在每次汇率变化后,枚举中间点,取结果的最小值

1≤n≤1e5   1≤q≤1e5  -> 枚举中间点的最坏情况 n*q<=1e10  超时

#include<bits/stdc++.h>
using namespace std;
int n,m,q;
typedef long long ll;
const long long INF=1e18;
typedef pair<ll,int> PII;
const int N=1e5+5,M=N*4;
int h1[N],h2[N],e[M],ne[M],idx;
ll w1[M],w2[M];
ll a[N];
ll dis1[N],dis2[N];
bool vis[N];
void add1(int a,int b,ll c)
{
	e[idx]=b;
	w1[idx]=c;
	ne[idx]=h1[a];
	h1[a]=idx++;
}
void add2(int a,int b,ll c)
{
	e[idx]=b;
	w2[idx]=c;
	ne[idx]=h2[a];
	h2[a]=idx++;
}
void d_1()//正向 
{
	memset(vis,false,sizeof vis);
	dis1[1]=0;
	priority_queue<PII,vector<PII>,greater<PII> >heap;
	heap.push({0,1});
	while(heap.size())
	{
		PII t=heap.top();heap.pop();
		int ver=t.second;
		ll distance=t.first;
		if(vis[ver]) continue;
		vis[ver]=true; 
		for(int i=h1[ver];i!=-1;i=ne[i])
		{
			int j=e[i];
			if(dis1[j]>distance+w1[i])
			{
				dis1[j]=distance+w1[i];
				heap.push({dis1[j],j});
			}
		}
	}
}
void d_2()//反向 
{
	memset(vis,false,sizeof vis);
	dis2[n]=0;
	priority_queue<PII,vector<PII>,greater<PII> >heap;
	heap.push({0,n});
	while(heap.size())
	{
		PII t=heap.top();heap.pop();
		int ver=t.second;
		ll distance=t.first;
		if(vis[ver]) continue;
		vis[ver]=true; 
		for(int i=h2[ver];i!=-1;i=ne[i])
		{
			int j=e[i];
			if(dis2[j]>distance+w2[i])
			{
				dis2[j]=distance+w2[i];
				heap.push({dis2[j],j});
			}
		}
	}
}
void solve()
{
	int x;ll na;cin>>x>>na;
	a[x]=na;
	ll res=1e18;
	for(int i=1;i<=n;i++)
	{
		if(dis1[i]==INF||dis2[i]==INF) continue;
		ll t=dis1[i]+ceil(dis2[i]*1.0/a[i]);
		res=min(res,t);
	}
	cout<<res<<endl;
}
int main()
{
	cin>>n>>m>>q;
	memset(h1,-1,sizeof h1);
	memset(h2,-1,sizeof h2);
	memset(dis1,0x3f,sizeof dis1);
	memset(dis2,0x3f,sizeof dis2);
	for(int i=1;i<=m;i++)
	{
		int u,v;ll c,d;cin>>u>>v>>c>>d;
		add1(u,v,c),add2(v,u,d);	
	}
	for(int i=1;i<=n;i++) cin>>a[i];
	d_1();
	d_2();
	while(q--) solve();	
}

考虑如何优化: 

        我们可以发现每次只变动一个点的汇率,也就是说所有点中只有一个点的花费是变化的,所以可以把所有点作为中间点的结果存起来,然后每次更新汇率变更的点的花费

        可以考虑用STL的multiset容器,可以自动去重(更正:set可以去重,multiset不可以,两者均有序)和排序,操作时间复杂度为o(logn)

multiset<ll> st;
for(int i=1;i<=n;i++)
{
	if(dis1[i]==INF||dis2[i]==INF) continue;
	ll t=dis1[i]+ceil(dis2[i]*1.0/a[i]);
	st.insert(t);
}
while(q--)
{
	int x;ll na;cin>>x>>na;
	if(dis1[x]!=INF&&dis2[x]!=INF)
	{
		st.erase(st.find(dis1[x]+ceil(dis2[x]*1.0/a[x])));
		a[x]=na;
		st.insert(dis1[x]+ceil(dis2[x]*1.0/a[x]));
	}
	cout<<*st.begin()<<endl;	
}

        在求完最短路后,对于其中和两边联通的点,存入其花费

        对于每次更新,将对应原来位置的花费删除,并加入新的花费,最终取最小值即可

全部代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,q;
typedef long long ll;
const long long INF=0x3f3f3f3f3f3f3f3f;
typedef pair<ll,int> PII;
const int N=1e5+5,M=N*4;
int h1[N],h2[N],e[M],ne[M],idx;
ll w1[M],w2[M];
ll a[N];
ll dis1[N],dis2[N];
bool vis[N];
void add1(int a,int b,ll c)
{
	e[idx]=b;
	w1[idx]=c;
	ne[idx]=h1[a];
	h1[a]=idx++;
}
void add2(int a,int b,ll c)
{
	e[idx]=b;
	w2[idx]=c;
	ne[idx]=h2[a];
	h2[a]=idx++;
}
void d_1()
{
	memset(vis,false,sizeof vis);
	dis1[1]=0;
	priority_queue<PII,vector<PII>,greater<PII> >heap;
	heap.push({0,1});
	while(heap.size())
	{
		PII t=heap.top();heap.pop();
		int ver=t.second;
		ll distance=t.first;
		if(vis[ver]) continue;
		vis[ver]=true; 
		for(int i=h1[ver];i!=-1;i=ne[i])
		{
			int j=e[i];
			if(dis1[j]>distance+w1[i])
			{
				dis1[j]=distance+w1[i];
				heap.push({dis1[j],j});
			}
		}
	}
}
void d_2()
{
	memset(vis,false,sizeof vis);
	dis2[n]=0;
	priority_queue<PII,vector<PII>,greater<PII> >heap;
	heap.push({0,n});
	while(heap.size())
	{
		PII t=heap.top();heap.pop();
		int ver=t.second;
		ll distance=t.first;
		if(vis[ver]) continue;
		vis[ver]=true; 
		for(int i=h2[ver];i!=-1;i=ne[i])
		{
			int j=e[i];
			if(dis2[j]>distance+w2[i])
			{
				dis2[j]=distance+w2[i];
				heap.push({dis2[j],j});
			}
		}
	}
}
int main()
{
	cin>>n>>m>>q;
	memset(h1,-1,sizeof h1);
	memset(h2,-1,sizeof h2);
	memset(dis1,0x3f,sizeof dis1);
	memset(dis2,0x3f,sizeof dis2);
	for(int i=1;i<=m;i++)
	{
		int u,v;ll c,d;cin>>u>>v>>c>>d;
		add1(u,v,c),add2(v,u,d);	
	}
	for(int i=1;i<=n;i++) cin>>a[i];
	d_1();
	d_2();
	multiset<ll> st;
	for(int i=1;i<=n;i++)
	{
		if(dis1[i]==INF||dis2[i]==INF) continue;
		ll t=dis1[i]+ceil(dis2[i]*1.0/a[i]);
		st.insert(t);
	}
	while(q--)
	{
		int x;ll na;cin>>x>>na;
		if(dis1[x]!=INF&&dis2[x]!=INF)
		{
			st.erase(st.find(dis1[x]+ceil(dis2[x]*1.0/a[x])));
			a[x]=na;
			st.insert(dis1[x]+ceil(dis2[x]*1.0/a[x]));
		}
		cout<<*st.begin()<<endl;	
	}
}

 第五题   思维+递归 

        正序求计算结果,递归求偏导结果 ,先把每个节点的内容以及节点的关系记录,如何按正向顺序计算结果,反向顺序递归计算偏导结果

对于一个节点的定义
        一个节点代表一个自变量或式子,储存自变量的值或者式子计算的值,以及该节点对应的操作符,无论求计算结果还是偏导结果,我们都需要知道这个节点是谁计算组合得来的,所以记录组成其的0/1/2个节点

        另外,这道题比较坑的地方就是没有说输入数据是按顺序给的ヽ(#`Д´)ノ,所以我们还需要判断出哪个节点是最后的式子,所以加一个标记ne,表示其是否存在后继节点,若不存在则为最后的式子

struct Node
{
	double w;//值
	int op;//操作符
	int front[4];//前面的0/1/2个节点
	bool ne; 
}node[N];

         记得我们最开始说输入顺序是不定的,所以我们先储存节点,后排序,同时初始化节点信息

for(int i=0;i<n;i++)
	{
		int op;scanf("%d",&op);
		node[i].op=op;	
		if(op==0)
		{
			double x;scanf("%lf",&x);
			node[i].w=x;
			node[i].front[1]=node[i].front[2]=-1;
			vc.push_back(i);
		}
		else if(op==1)
		{
			int x1,x2;scanf("%d%d",&x1,&x2);
			node[i].front[1]=x1;
			node[i].front[2]=x2;
			node[x1].ne=true;
			node[x2].ne=true;
		}
		else if(op==2)
		{
			int x1,x2;scanf("%d%d",&x1,&x2);
			node[i].front[1]=x1;
			node[i].front[2]=x2;
			node[x1].ne=true;
			node[x2].ne=true;
		}
		else if(op==3)
		{
			int x1,x2;scanf("%d%d",&x1,&x2);
			node[i].front[1]=x1;
			node[i].front[2]=x2;
			node[x1].ne=true;
			node[x2].ne=true;
		}
		else if(op==4)
		{
			int x;scanf("%d",&x);
			node[i].front[1]=x;
			node[i].front[2]=-1;
			node[x].ne=true;
		}
		else if(op==5)
		{
			int x;scanf("%d",&x);
			node[i].front[1]=x;
			node[i].front[2]=-1;
			node[x].ne=true;
		}
		else if(op==6)
		{
			int x;scanf("%d",&x);
			node[i].front[1]=x;
			node[i].front[2]=-1;
			node[x].ne=true;
		}
	}

        如何我们观察一下应该如何找顺序

         类似于BFS的写法,从最终的式子节点开始,对于一个节点,先拓展其前面的1/2个节点,并有序存储,注意不要重复记录

(此处有一点:拓展时必须先拓展其第二个节点,即如果为x+y时必须先写y,要不会错一个测试数据。。具体原因我也不知道,参考网上代码改对的这一测试点˚‧º·(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )‧º·˚)

int t=-1;
for(int i=0;i<n;i++) 
	if(!node[i].ne) 
	{
		t=i;
		break;
	}
q.push(t);
v.push_back(t);
while(!q.empty())
{
	int top=q.front();q.pop();
	if(node[top].front[2]!=-1)
	{
		q.push(node[top].front[2]);
		if(!vis[node[top].front[2]])
		{
			vis[node[top].front[2]]=true;
			v.push_back(node[top].front[2]);
		}
	}
	if(node[top].front[1]!=-1)
	{
		q.push(node[top].front[1]);
		if(!vis[node[top].front[1]])
		{
			vis[node[top].front[1]]=true;
			v.push_back(node[top].front[1]);
		}
	}
}

        按从自变量开始的顺序进行正向计算,模拟即可

for(int i=n-1;i>=0;i--)
	{
		int u=v[i];
		int op=node[u].op;
		if(op==0) continue; 
		else if(op==1)
		{
			int x1=node[u].front[1],x2=node[u].front[2];
			node[u].w=node[x1].w+node[x2].w;
		}
		else if(op==2)
		{
			int x1=node[u].front[1],x2=node[u].front[2];
			node[u].w=node[x1].w-node[x2].w;
		}
		else if(op==3)
		{
			int x1=node[u].front[1],x2=node[u].front[2];
			node[u].w=node[x1].w*node[x2].w;
		}
		else if(op==4)
		{
			int x=node[u].front[1];
			node[u].w=exp(node[x].w);
		}
		else if(op==5)
		{
			int x=node[u].front[1];
			node[u].w=log(node[x].w);
		}
		else if(op==6)
		{
			int x=node[u].front[1];
			node[u].w=sin(node[x].w);
		}
	}

        从最终式子开始,递归求偏导值

double dfs(int u,int q)
{
	int op=node[u].op;
	if(op==0)
	{
		if(u==q) return 1;
		else return 0;
	}
	else if(op==1)
	{
		int x1=node[u].front[1],x2=node[u].front[2];
		double tr=dfs(x1,q)+dfs(x2,q);
		return tr;
	}
	else if(op==2)
	{
		int x1=node[u].front[1],x2=node[u].front[2];
		double tr=dfs(x1,q)-dfs(x2,q);
		return tr;
	}
	else if(op==3)
	{
		int x1=node[u].front[1],x2=node[u].front[2];
		double tr1=dfs(x1,q),tr2=dfs(x2,q);
		double tres=node[x1].w*tr2+node[x2].w*tr1;
		return tres;
	}
	else if(op==4)
	{
		int x=node[u].front[1];
		double tr=dfs(x,q);
		double tres=exp(node[x].w)*tr;
		return tres;
	}
	else if(op==5)
	{
		int x=node[u].front[1];
		double tr=dfs(x,q);
		if(tr==0) return 0;
		double tres=(1.0/node[x].w)*tr;
		return tres;
	}
	else if(op==6)
	{
		int x=node[u].front[1];
		double tr=dfs(x,q);
		double tres=cos(node[x].w)*tr;
		return tres;
	}	
}

完整代码: 

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5;
int n;
struct Node
{
	double w;//值
	int op;//操作符
	int front[4];//前面的0/1/2个节点
	bool ne; 
}node[N];
vector<int> vc;//自变量 
queue<int> q;//层次遍历对节点排序 
vector<int> v;//倒序存放节点 
bool vis[N];
double dfs(int u,int q)
{
	int op=node[u].op;
	if(op==0)
	{
		if(u==q) return 1;
		else return 0;
	}
	else if(op==1)
	{
		int x1=node[u].front[1],x2=node[u].front[2];
		double tr=dfs(x1,q)+dfs(x2,q);
		return tr;
	}
	else if(op==2)
	{
		int x1=node[u].front[1],x2=node[u].front[2];
		double tr=dfs(x1,q)-dfs(x2,q);
		return tr;
	}
	else if(op==3)
	{
		int x1=node[u].front[1],x2=node[u].front[2];
		double tr1=dfs(x1,q),tr2=dfs(x2,q);
		double tres=node[x1].w*tr2+node[x2].w*tr1;
		return tres;
	}
	else if(op==4)
	{
		int x=node[u].front[1];
		double tr=dfs(x,q);
		double tres=exp(node[x].w)*tr;
		return tres;
	}
	else if(op==5)
	{
		int x=node[u].front[1];
		double tr=dfs(x,q);
		if(tr==0) return 0;
		double tres=(1.0/node[x].w)*tr;
		return tres;
	}
	else if(op==6)
	{
		int x=node[u].front[1];
		double tr=dfs(x,q);
		double tres=cos(node[x].w)*tr;
		return tres;
	}	
}
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		int op;scanf("%d",&op);
		node[i].op=op;	
		if(op==0)
		{
			double x;scanf("%lf",&x);
			node[i].w=x;
			node[i].front[1]=node[i].front[2]=-1;
			vc.push_back(i);
		}
		else if(op==1)
		{
			int x1,x2;scanf("%d%d",&x1,&x2);
			node[i].front[1]=x1;
			node[i].front[2]=x2;
			node[x1].ne=true;
			node[x2].ne=true;
		}
		else if(op==2)
		{
			int x1,x2;scanf("%d%d",&x1,&x2);
			node[i].front[1]=x1;
			node[i].front[2]=x2;
			node[x1].ne=true;
			node[x2].ne=true;
		}
		else if(op==3)
		{
			int x1,x2;scanf("%d%d",&x1,&x2);
			node[i].front[1]=x1;
			node[i].front[2]=x2;
			node[x1].ne=true;
			node[x2].ne=true;
		}
		else if(op==4)
		{
			int x;scanf("%d",&x);
			node[i].front[1]=x;
			node[i].front[2]=-1;
			node[x].ne=true;
		}
		else if(op==5)
		{
			int x;scanf("%d",&x);
			node[i].front[1]=x;
			node[i].front[2]=-1;
			node[x].ne=true;
		}
		else if(op==6)
		{
			int x;scanf("%d",&x);
			node[i].front[1]=x;
			node[i].front[2]=-1;
			node[x].ne=true;
		}
	}
	int t=-1;
	for(int i=0;i<n;i++) 
		if(!node[i].ne) 
		{
			t=i;
			break;
		}
	q.push(t);
	v.push_back(t);
	while(!q.empty())
	{
		int top=q.front();q.pop();
		if(node[top].front[2]!=-1)
		{
			q.push(node[top].front[2]);
			if(!vis[node[top].front[2]])
			{
				vis[node[top].front[2]]=true;
				v.push_back(node[top].front[2]);
			}
		}
		if(node[top].front[1]!=-1)
		{
			q.push(node[top].front[1]);
			if(!vis[node[top].front[1]])
			{
				vis[node[top].front[1]]=true;
				v.push_back(node[top].front[1]);
			}
		}
	}
	for(int i=n-1;i>=0;i--)
	{
		int u=v[i];
		int op=node[u].op;
		if(op==0) continue; 
		else if(op==1)
		{
			int x1=node[u].front[1],x2=node[u].front[2];
			node[u].w=node[x1].w+node[x2].w;
		}
		else if(op==2)
		{
			int x1=node[u].front[1],x2=node[u].front[2];
			node[u].w=node[x1].w-node[x2].w;
		}
		else if(op==3)
		{
			int x1=node[u].front[1],x2=node[u].front[2];
			node[u].w=node[x1].w*node[x2].w;
		}
		else if(op==4)
		{
			int x=node[u].front[1];
			node[u].w=exp(node[x].w);
		}
		else if(op==5)
		{
			int x=node[u].front[1];
			node[u].w=log(node[x].w);
		}
		else if(op==6)
		{
			int x=node[u].front[1];
			node[u].w=sin(node[x].w);
		}
	}
	printf("%.3lf\n",node[v[0]].w*1.0);
	for(int i=0;i<vc.size();i++)
	{
		printf("%.3lf",dfs(t,vc[i])*1.0);
		if(i!=vc.size()-1) printf(" ");
	}
}

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vic.GoodLuck

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值