【刷题】紫书第六章:数据结构基础(例题部分)

版权声明:欢迎评论交流,转载请注明原作者。 https://blog.csdn.net/m0_37809890/article/details/83140781

截图打卡

在这里插入图片描述

总结

  1. map的operator[]操作会在目标元素不存在时新建一个元素,无副作用的检验元素是否存在应该使用map.count()
  2. 跳过了本章指针建树与手动内存池的部分,以后再学。
  3. 多组数据题,完全可以while(init()),init包括了初始化与读入工作。
  4. list.insert(iter,val),在iter左边插入,不改变iter,返回被插入位置的迭代器。
  5. 拓扑排序:dfs,访问完一个节点之后把它加在拓扑序的首部,这个方法也能用来判环。
  6. 网格与点转化,带离散化的情况,参考第18题
  7. 第20题,刘老师有更快的方法,日后回来看。
  8. 要学会合理建图(废话)

题目

  1. uva210 模拟
    大模拟题,读清题意,想好数据结构,单元测试
  2. uva514 栈原理
    用类似于双指针的操作。
  3. uva442 表达式解析
    表达式解析的常规套路:想好栈中元素,想好元素初值,画自动机
    	int ans = 0;
    	int sl = 0, sr = 0;
    	stack<pair<int,int>> st;
    	for(auto c:expr)
    	{
    		if(isalpha(c))
    		{
    			if(sl==0)
    			{
    				sl = lef[c], sr = rig[c];
    			}
    			else
    			{
    				ans += sl * lef[c] * rig[c];
    				sr = rig[c];
    			}
    		}
    		else if(c=='(')	
    		{
    			st.emplace(sl,sr);
    			sl = 0, sr = 0;
    		}
    		else if(c==')')
    		{
    			int xl = st.top().first, xr = st.top().second; st.pop();
    			ans += xl*max(xr,sl)*sr;
    			if(xl) sl=xl;
    			if(sr==0) sr=xr;
    		}
    		//printf("sl=%d sr=%d stack=%d\n",sl,sr,st.size() );
    	}
    
  4. uva11988 链表
    熟悉std::list的操作
  5. uva12657
    双向链表,很好的一道题,以后可以再写一遍。
    加标记,提前保存,函数扩展。
    /* LittleFall : Hello! */
    #include <bits/stdc++.h>
    using namespace std; using ll = long long; inline int read();
    const int M = 500016, MOD = 1000000007;
    
    int pre[M], nxt[M];
    inline void link(int x, int y)
    {
    	nxt[x]=y;
    	pre[y]=x;
    }
    int main(void)
    {
    	int n,m,kase=0;
    	while(scanf("%d%d",&n,&m)!=EOF)
    	{
    		for(int i=1;i<=n;++i)
    		{
    			pre[i] = i-1;
    			nxt[i] = i+1;
    		}
    		nxt[0] = 1, pre[n+1] = n;
    		int inv = 0;
    		while(m--)
    		{
    			int op = read();
    			if(op==4) 
    			{
    				inv^=1;
    				continue;
    			}
    			int x = read(), y = read();
    			int lx = pre[x], ly = pre[y], rx = nxt[x], ry = nxt[y];
    			if(op<3 && inv) op = 3 - op;
    			if(op==1 && nxt[x]!=y)
    			{
    				link(lx,rx);
    				link(ly,x);
    				link(x,y);
    			}
    			if(op==2 && pre[x]!=y)
    			{
    				link(lx,rx);
    				link(y,x);
    				link(x,ry);
    			}
    			if(op==3)
    			{
    				if(x==pre[y])
    				{
    					link(lx,y);
    					link(y,x);
    					link(x,ry);
    				}
    				else if(y==pre[x])
    				{
    					link(ly,x);
    					link(x,y);
    					link(y,rx);
    				}
    				else
    				{
    					link(lx,y);
    					link(ly,x);
    					link(y,rx);
    					link(x,ry);
    				}
    			}
    		}
    		int cnt = 1;
    		ll ans = 0;
    		for(int i=nxt[0];i!=n+1;i=nxt[i])
    		{
    			//printf("%d\n",i );
    			if(cnt^inv) ans += i;
    			cnt^=1;
    		}
    		printf("Case %d: %lld\n",++kase,ans );
    	}
        return 0;
    }
    
  6. uva 679
    算结论题
  7. uva 122
    输入处理
  8. uva 548 由中序和后序建树,经典题
    int n, nxt = 0; //新插位置
    int in_order[M], post_order[M], anti_in[M]; //中序,后序
    int ans = 0, miamount = INT_MAX, mival = INT_MAX;
    struct Node
    {
    	int val;
    	int amount;
    	vector<int> son;
    }node[M];
    int solve(int in_lef, int post_lef, int length) //中序左边界,后序左边界,长度
    {
    	int n_id = nxt++; //节点存储编号
    	node[n_id].val = post_order[post_lef+length-1]; //根节点的值
    	int in_rt = anti_in[node[n_id].val]; //获得根节点在中序中的下标
    
    	int lef_len = in_rt - in_lef, rig_len = length - 1 - lef_len; //左右子树的节点数
    	if(lef_len) node[n_id].son.push_back(solve(in_lef, post_lef, lef_len));
    	if(rig_len) node[n_id].son.push_back(solve(in_rt+1, post_lef+lef_len, rig_len));
    	return n_id;
    }
    void dfs(int now, int lst) //当前节点,之前路径上的权值和
    {
    	node[now].amount = node[now].val + lst;
    	if(node[now].son.empty() && (node[now].amount<miamount || 
    		(node[now].amount == miamount && node[now].val<mival)))
    	{
    		ans = now;
    		miamount = node[now].amount;
    		mival = node[now].val;
    	}
    	for(auto nxt:node[now].son)
    		dfs(nxt, node[now].amount);
    }
    inline bool init() //初始化与读入,失败返回0
    {
    	nxt = n = 0;
    	ans = 0;
    	miamount = mival = INT_MAX;
    	memset(node,0,sizeof(node));
    	string tmp;
    	stringstream sin;
    	getline(cin,tmp); if(tmp=="") return 0; sin = stringstream(tmp);
    	while(sin >> in_order[n+1]) 
    		++n;
    	getline(cin,tmp); sin = stringstream(tmp);
    	for(int i=1;i<=n;++i) 
    		sin >> post_order[i];
    
    	return n;
    }
    int main(void)
    {
    	#ifdef _LITTLEFALL_
    	freopen("in.txt","r",stdin);
        #endif
    	while(init())
    	{
    		for(int i=1;i<=n;++i) 
    			anti_in[in_order[i]] = i;
    		solve(1,1,n);
    		dfs(0,0);
    		printf("%d\n",node[ans].val );
    	}
    
        return 0;
    }
    
  9. Uva 839 经典结构,输入,递归,传递引用,返回
  10. uva 699 递归
  11. uva 297 四分树
    年轻的时候做过这道题,没做出来。
    把四分树表示的图像画出来就好了。
  12. uva572 dfs求连通块
  13. uva1103 代码结构要明确,dfs函数写一个就行。
    /* LittleFall : Hello! */
    #include <bits/stdc++.h>
    using namespace std; using ll = long long; inline int read();
    const int M = 256, MOD = 1000000007;
    
    const int go[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
    const char ch[7] = {'W','A','K','J','S','D'};
    int mp[M][M],tag[M][M],n,m;
    int ans[M*M];
    char out[M*M];
    //把相邻的颜色为co的都打上st的标记
    void dfs(int i,int j,int co,int st)
    {
    	tag[i][j] = st;
    	for(int k=0;k<4;++k)
    	{
    		int ni = i+go[k][0], nj = j+go[k][1];
    		if(ni>=0 && ni<=n+1 && nj>=0 && nj<=m+1 && mp[ni][nj]==co && tag[ni][nj]==0)
    			dfs(ni,nj,co,st);
    	}
    	return;
    }
    /*Process Function*/
    int init()
    {
    	scanf("%d%d",&n,&m);
    	if(n==0) return 0;
    	m<<=2;
    	memset(mp,0,sizeof(mp));
    	memset(tag,0,sizeof(tag));
    	memset(ans,0,sizeof(ans));
    	memset(out,0,sizeof(out));
    	char tmp[64];
    	for(int i=1;i<=n;++i)
    	{
    		scanf("%s",tmp+1);
    		for(int j=1;tmp[j];++j)
    		{
    			int num = isalpha(tmp[j])?tmp[j]-'a'+10:tmp[j]-'0';
    			for(int k=0;k<4;++k)
    				mp[i][(j-1)*4+1+k] = (num>>(3-k))&1;
    		}
    	}
    	return 1;
    }
    int main(void)
    {
    	int kase = 0;
    	while(init())
    	{
    		int bls=0;
    		for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
    		{
    			if(mp[i][j]==1 && tag[i][j]==0)
    				dfs(i,j,1,++bls);
    		}
    
    		dfs(0,0,0,-1); 
    		for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(mp[i][j]==1)
    		{
    			for(int k=0;k<4;++k)
    			{
    				int ni=i+go[k][0],nj=j+go[k][1];
    				if(mp[ni][nj]==0 && tag[ni][nj]==0)
    				{
    					++ans[tag[i][j]];
    					dfs(ni,nj,0,tag[i][j]);
    				}
    			}
    		}
    		for(int i=1;i<=bls;++i)
    			out[i]=ch[ans[i]];
    		sort(out+1,out+bls+1);
    		printf("Case %d: %s\n",++kase,out+1 );
    	}
    
        return 0;
    }
    
  14. uva816 带方向的迷宫
    认清问题实质,然后bfs
  15. uva10305 拓扑排序
    dfs,把新访问完的放在最前面
  16. uva10129 欧拉路
    1. 无向图,欧拉圈:没有奇度数点。
    2. 无向图,欧拉路:没有奇度数点或只有两个
    3. 有向图,欧拉圈:所有节点入度=出度
    4. 有向图,欧拉路:满足上述条件,或者有一节点入度=出度+1且有一节点出度=入度+1,其它节点全部入度=出度。
    5. 图必须连通(有向图为底图连通)
  17. uva10562 递归
    注意字符集不一定是小写字母,isprint()判断可打印字符(包括空白字符),isgraph()不包括空白字符
  18. UVA - 12171 Sculpture 离散化,网格与点的转化
  19. uva1572 建图,判环
    以字母+符号为点,正方形看成边,建立一个有向图。注意每条边的起点不变,终点变成它的共轭。当且仅当图中有环时输出yes。
    set<int> edg[M];
    int vis[M]; //0未访问,1正在访问,2访问结束
    bool dfs(int u)
    {
    	vis[u] = 1;
    	for(auto v:edg[u])
    	{
    		if(vis[v]==1) 
    			return false;
    		else if(vis[v]==0) 
    			if(!dfs(v)) return false;
    	}
    	vis[u] = 2;
    	return true;
    }
    bool noloop()
    {
    	for(int i=0;i<52;++i)
    		if( !vis[i] && !dfs(i) ) return false;
    	return true;
    }
    int init()
    {
    	for(int i=0;i<M;++i)
    		edg[i].clear();
    	memset(vis,0,sizeof(vis));
    
    	int n;
    	if(scanf("%d",&n)==-1) return 0;
    	char tmp[10];
    	for(int i=0;i<n;++i)
    	{
    		scanf("%s",tmp);
    		for(int id1=0;id1<4;++id1)
    		{
    			for(int id2=id1+1;id2<4;++id2) if(tmp[id1*2]!='0' && tmp[id2*2]!='0')
    			{
    				int u = (tmp[id1*2]-'A')*2 + (tmp[id1*2+1]=='+');
    				int v = (tmp[id2*2]-'A')*2 + (tmp[id2*2+1]=='+');
    				edg[u].insert(v^1), edg[v].insert(u^1);
    			}
    		}
    	}
    	return n;
    }
    int main(void)
    {
    	#ifdef _LITTLEFALL_
    	freopen("in.txt","r",stdin);
        #endif
    
    	while(init())
    	{
    		printf("%s\n",noloop()?"bounded":"unbounded" );
    	}
    
        return 0;
    }
    
  20. uva1599 bfs
    给一无向图,每条边都有一个权值。求起点到终点的一条路径,要求经过的边数最小,且边权序列的字典序最小。
    反向bfs一遍,然后从起点开始逐距离把所有边权最小的点的记录下来,每次仅从边权最小的点向后转移。注意有自环或重边,所以需要对记录去重,否则记录数量会变成指数。
    int n,m;
    struct Node{
    	int fst;
    	int dis; //距终点的距离
    }nod[N];
    struct Edge{
    	int pnt,nxt,pri;
    }edg[M];
    int ect;
    void addEdge(int u,int v,int p)
    {
    	edg[++ect].pnt = v;
    	edg[ect].pri = p;
    	edg[ect].nxt = nod[u].fst;
    	nod[u].fst = ect;
    }
    
    set<int> per[N]; //距离终点i的可选择序列
    int init()
    {
    	if(scanf("%d%d",&n,&m)==-1) return 0;
    
    	memset(nod,-1,sizeof(nod));
    	memset(edg,0,sizeof(edg));
    	for(int i=0;i<N;++i) per[i].clear();
    
    	ect = 0;
    	while(m--)
    	{
    		int a=read(),b=read(),c=read();
    		addEdge(a,b,c);
    		addEdge(b,a,c);
    	}
    	return 1;
    }
    
    void bfs(int st)
    {
    	queue<int> q;
    	nod[st].dis = 0; 
    	q.push(st);
    	while(!q.empty())
    	{
    		int u = q.front(); q.pop();
    		for(int vd=nod[u].fst; ~vd; vd=edg[vd].nxt)
    		{
    			int v = edg[vd].pnt;
    			if(nod[v].dis == -1)
    			{
    				nod[v].dis = nod[u].dis+1;
    				q.push(v);
    			}
    		}
    	}
    }
    
    int main(void)
    {
    	#ifdef _LITTLEFALL_
    	freopen("in.txt","r",stdin);
        #endif
    
    	while(init())
    	{
    		bfs(n);
    
    		int tot = nod[1].dis;
    		printf("%d\n",tot );
    		
    		per[tot].insert(1);
    		for(int dis = tot; dis; --dis)
    		{
    			int ans = MOD;
    			for(auto u:per[dis])
    				for(int vd=nod[u].fst; ~vd; vd=edg[vd].nxt)
    					if(nod[ edg[vd].pnt ].dis == dis-1)
    						ans = min(ans, edg[vd].pri);
    			for(auto u:per[dis])
    				for(int vd=nod[u].fst; ~vd; vd=edg[vd].nxt)
    				{
    					int v = edg[vd].pnt;
    					if(nod[v].dis == dis-1 && edg[vd].pri==ans)
    						per[dis-1].insert(v);
    				}
    			printf("%d%c",ans,dis==1?'\n':' ' );
    		}
    	}
    
        return 0;
    }
    
  21. uva506 大模拟 题目没给数据范围,应该在10000左右.
  22. uva11853 简单计算几何,dfs
    正方形内有n个圆形障碍物,问能否从左边界走到右边界,如果可以,求最北边的进入点和离去点。
    把每个障碍物视作一个点,如果两个圆相交,那么它们有边相连。当且仅当与上边界相交的圆连通的圆与下边界相交时,无法走通。能走通时,最北边的进入点就是与上边界连通的圆与左边界的最南方交点,离去点同理。
    int n, ect;
    struct Node{
    	int fst; //graph
    	int x,y,r; //circle
    	int vis; //dfs
    }nod[M];
    struct Edge{
    	int nxt,pnt;
    }edg[M];
    inline void addEdge(int a, int b)
    {
    	edg[++ect].pnt = b;
    	edg[ect].nxt = nod[a].fst;
    	nod[a].fst = ect;
    }
    
    int fail = 0;
    double lin = 1000, lout = 1000;
    void dfs(int u)
    {
    	nod[u].vis = 1;
    	for(int vd=nod[u].fst; vd; vd=edg[vd].nxt)
    	{
    		int v = edg[vd].pnt;
    		if(!nod[v].vis) dfs(v);
    	}
    	int r = nod[u].r, x = nod[u].x, y = nod[u].y;
    	if(y-r<=0) fail = 1;
    	if(x-r<=0) 
    		lin = min(lin,y-sqrt(r*r-x*x));
    	if(x+r>=1000)
    		lout = min(lout,y-sqrt(r*r-(1000-x)*(1000-x)));
    }
    int init()
    {
    	//init
    	n = ect = fail = 0;
    	lin = lout = 1000.0;
    	memset(nod,0,sizeof(nod));
    	memset(edg,0,sizeof(edg));
    
    	//read
    	if(scanf("%d",&n)==-1) return 0;
    	for(int i=1;i<=n;++i)
    	{
    		nod[i].x = read();
    		nod[i].y = read();
    		nod[i].r = read();
    	}
    
    	//build
    	for(int i=1;i<=n;++i)
    	{
    		int ax = nod[i].x, ay = nod[i].y, ar=nod[i].r;
    		for(int j=i+1;j<=n;++j)
    		{
    			int bx = nod[j].x, by = nod[j].y, br=nod[j].r;
    			if((ax-bx)*(ax-bx)+(ay-by)*(ay-by)<=(ar+br)*(ar+br)) //不相离
    				addEdge(i,j), addEdge(j,i);
    		}
    	}
    	return 1;
    }
    int main(void)
    {
    	#ifdef _LITTLEFALL_
    	freopen("in.txt","r",stdin);
        #endif
    
    	while(init())
    	{
    		for(int i=1;i<=n;++i)
    			if(!nod[i].vis && nod[i].y+nod[i].r>=1000)
    				dfs(i);
    		if(fail)
    			printf("IMPOSSIBLE\n");
    		else
    			printf("0.00 %.2f 1000.00 %.2f\n",lin,lout );
    	}
    
        return 0;
    }
    

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/83140781